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 38baf7f43e..756e59305d 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -68,8 +68,13 @@ TDeviceMap g_DeviceMap; // STATE_TO_SAVE typedef std::map TFileNameMap; -TFileNameMap g_FileNameMap; -u32 g_LastDeviceID; + +#define IPC_MAX_FDS 0x18 +#define ES_MAX_COUNT 2 +IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS]; +bool es_inuse[ES_MAX_COUNT]; +IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT]; + typedef std::deque ipc_msg_queue; static ipc_msg_queue request_queue; // ppc -> arm @@ -78,14 +83,27 @@ static ipc_msg_queue reply_queue; // arm -> ppc void Init() { _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init"); + + u32 i; + for(i=0; iIsHardware()) + { + // close all files and delete their resources + g_FdMap[i]->Close(0, true); + delete g_FdMap[i]; + } + g_FdMap[i] = NULL; + } + TDeviceMap::iterator itr = g_DeviceMap.begin(); while (itr != g_DeviceMap.end()) { @@ -111,21 +139,17 @@ void Reset(bool _bHard) // Force close itr->second->Close(0, true); // Hardware should not be deleted unless it is a hard reset - if (_bHard || !itr->second->IsHardware()) + if (_bHard) delete itr->second; } ++itr; } - // Skip hardware devices if not a hard reset - itr = (_bHard) ? g_DeviceMap.begin() : g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID); - // Erase devices - g_DeviceMap.erase(itr, g_DeviceMap.end()); - g_FileNameMap.clear(); - + if (_bHard) + { + g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end()); + } request_queue.clear(); reply_queue.clear(); - - g_LastDeviceID = IPC_FIRST_FILEIO_ID; } void Shutdown() @@ -135,41 +159,52 @@ void Shutdown() void SetDefaultContentFile(const std::string& _rFilename) { - CWII_IPC_HLE_Device_es* pDevice = - (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); - if (pDevice) - pDevice->LoadWAD(_rFilename); + TDeviceMap::const_iterator itr = g_DeviceMap.begin(); + while(itr != g_DeviceMap.end()) + { + if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0) + { + ((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename); + } + ++itr; + } } void ES_DIVerify(u8 *_pTMD, u32 _sz) { - CWII_IPC_HLE_Device_es* pDevice = - (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); - if (pDevice) - pDevice->ES_DIVerify(_pTMD, _sz); - else - ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available"); + CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz); } void SDIO_EventNotify() { CWII_IPC_HLE_Device_sdio_slot0 *pDevice = - (CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0"))); + (CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0")); if (pDevice) pDevice->EventNotify(); } +int getFreeDeviceId() +{ + u32 i; + for(i=0; isecond->GetDeviceName() == _rDeviceName) - return itr->first; + if (itr->second && itr->second->GetDeviceName() == _rDeviceName) + return itr->second; ++itr; } - return -1; + return NULL; } IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) @@ -177,17 +212,7 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) return g_DeviceMap[_ID]; - return NULL; -} - -void DeleteDeviceByID(u32 ID) -{ - IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID); - if (pDevice) - delete pDevice; - - g_DeviceMap.erase(ID); - g_FileNameMap.erase(ID); + return NULL; } // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE @@ -205,60 +230,82 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName void DoState(PointerWrap &p) { - p.Do(g_LastDeviceID); + p.Do(request_queue); + p.Do(reply_queue); - if (p.GetMode() == PointerWrap::MODE_READ) - { - TFileNameMap::const_iterator itr; - // Delete file Handles - itr = g_FileNameMap.begin(); - while (itr != g_FileNameMap.end()) - { - TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first); - if (devitr != g_DeviceMap.end()) + TDeviceMap::const_iterator itr; + + itr = g_DeviceMap.begin(); + while (itr != g_DeviceMap.end()) + { + if (itr->second->IsHardware()) { - if (devitr->second) - delete devitr->second; - g_DeviceMap.erase(itr->first); + itr->second->DoState(p); } ++itr; + } + + if (p.GetMode() == PointerWrap::MODE_READ) + { + u32 i; + for (i=0; iDoState(p); + } + } + else + { + g_FdMap[i] = NULL; + } } - // Load file names - p.Do(g_FileNameMap); - // Rebuild file handles - itr = g_FileNameMap.begin(); - while (itr != g_FileNameMap.end()) + for (i=0; ifirst] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second); - ++itr; + p.Do(es_inuse[i]); + u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(handleID); + + es_handles[i] = AccessDeviceByID(handleID); } } else { - p.Do(g_FileNameMap); - } - - p.Do(request_queue); - p.Do(reply_queue); - - - TDeviceMap::const_iterator itr; - //first, all the real devices - //(because we need fs to be deserialized first) - itr = g_DeviceMap.begin(); - while (itr != g_DeviceMap.end()) - { - if (itr->second->IsHardware()) - itr->second->DoState(p); - ++itr; - } - //then all the files - itr = g_DeviceMap.begin(); - while (itr != g_DeviceMap.end()) - { - if (!itr->second->IsHardware()) - itr->second->DoState(p); - ++itr; + u32 i; + for (i=0; iIsHardware() ? 1 : 0; + p.Do(isHw); + if (isHw) + { + u32 hwId = g_FdMap[i]->GetDeviceID(); + p.Do(hwId); + } + else + { + g_FdMap[i]->DoState(p); + } + } + } + for (i=0; iGetDeviceID(); + p.Do(handleID); + } } } @@ -267,67 +314,106 @@ void ExecuteCommand(u32 _Address) bool CmdSuccess = false; ECommandType Command = static_cast(Memory::Read_U32(_Address)); - int DeviceID = Memory::Read_U32(_Address + 8); - IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID); + volatile int DeviceID = Memory::Read_U32(_Address + 8); - INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) ", _Address, Command, DeviceID); + IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL; + + INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice); switch (Command) { case COMMAND_OPEN_DEVICE: - { - // 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); + DeviceID = getFreeDeviceId(); + + std::string DeviceName; + Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC)); - u32 Mode = Memory::Read_U32(_Address + 0x10); - DeviceID = GetDeviceIDByName(DeviceName); - - // check if a device with this name has been created already - if (DeviceName.find("/dev/") == std::string::npos || DeviceID == -1) - { - if (DeviceName.find("/dev/") == 0) + + WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID); + if (DeviceID >= 0) + { + if (DeviceName.find("/dev/es") == 0) + { + u32 j; + for (j=0; jOpen(_Address, Mode); + Memory::Write_U32(DeviceID, _Address+4); + break; + } + } + if(j == ES_MAX_COUNT) + { + Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4); + CmdSuccess = true; + } - pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("_Unimplemented_Device_"))); + } + else if (DeviceName.find("/dev/") == 0) + { + pDevice = GetDeviceByName(DeviceName); + if (pDevice) + { + g_FdMap[DeviceID] = pDevice; CmdSuccess = pDevice->Open(_Address, Mode); + INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + Memory::Write_U32(DeviceID, _Address+4); } else { - // create new file handle - u32 CurrentDeviceID = g_LastDeviceID; - pDevice = CreateFileIO(CurrentDeviceID, DeviceName); - g_DeviceMap[CurrentDeviceID] = pDevice; - g_FileNameMap[CurrentDeviceID] = DeviceName; - g_LastDeviceID++; - + WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); + pDevice = GetDeviceByName(std::string("_Unimplemented_Device_")); CmdSuccess = pDevice->Open(_Address, Mode); - - INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode); + g_FdMap[DeviceID] = pDevice; + Memory::Write_U32(DeviceID, _Address+4); } - } - else - { - // F|RES: prolly the re-open is just a mode change - pDevice = AccessDeviceByID(DeviceID); + } + else + { + IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName); CmdSuccess = pDevice->Open(_Address, Mode); - INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - } - } - break; + INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + if(Memory::Read_U32(_Address + 4) == DeviceID) + g_FdMap[DeviceID] = pDevice; + } + } + else + { + Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4); + CmdSuccess = true; + } + break; + } case COMMAND_CLOSE_DEVICE: - if (pDevice) + { + if (pDevice) { CmdSuccess = pDevice->Close(_Address); + + u32 j; + for (j=0; jIsHardware()) - DeleteDeviceByID(DeviceID); + delete pDevice; } else { @@ -335,50 +421,67 @@ void ExecuteCommand(u32 _Address) CmdSuccess = true; } break; - + } case COMMAND_READ: + { if (pDevice) + { CmdSuccess = pDevice->Read(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_WRITE: + { if (pDevice) + { CmdSuccess = pDevice->Write(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_SEEK: + { if (pDevice) + { CmdSuccess = pDevice->Seek(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_IOCTL: + { if (pDevice) + { CmdSuccess = pDevice->IOCtl(_Address); + } break; - + } case COMMAND_IOCTLV: + { if (pDevice) + { CmdSuccess = pDevice->IOCtlV(_Address); + } break; - + } default: + { _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address); break; + } } // It seems that the original hardware overwrites the command after it has been @@ -450,8 +553,7 @@ void Update() void UpdateDevices() { // Check if a hardware device must be updated - TDeviceMap::const_iterator itrEnd = g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID); - for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != itrEnd; ++itr) { + for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr) { if (itr->second->IsOpened() && itr->second->Update()) { break; } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h index 11420d1cdd..2e056b5bec 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h @@ -25,9 +25,9 @@ class IWII_IPC_HLE_Device; namespace WII_IPC_HLE_Interface { -#define IPC_FIRST_HARDWARE_ID 0 // first IPC device ID -#define IPC_FIRST_FILEIO_ID 33 // first IPC file ID - +#define IPC_FIRST_ID 0x00 // first IPC device ID +#define IPC_MAX_FILES 0x10 // first IPC file ID + // Init void Init(); @@ -46,14 +46,13 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz); void SDIO_EventNotify(); -int GetDeviceIDByName(const std::string& _rDeviceName); - -IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); - -void DeleteDeviceByID(u32 _ID); IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName); +IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName); +IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); +int getFreeDeviceId(); + // Update void Update(); 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 36709a084f..113b14cffb 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 @@ -39,7 +39,7 @@ class PointerWrap; #define FS_ENOENT2 (u32)-106 // File not found #define FS_ENFILE (u32)-107 // Too many fds open #define FS_EFBIG (u32)-108 // max block count reached? -#define FS_ENFILE2 (u32)-109 // Too many fds open +#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open #define FS_ENAMELEN (u32)-110 // pathname is too long #define FS_EFDOPEN (u32)-111 // FD is already open #define FS_EIO2 (u32)-114 // returned on ECC error @@ -47,6 +47,7 @@ class PointerWrap; #define FS_EDIRDEPTH (u32)-116 // max directory depth exceeded #define FS_EBUSY2 (u32)-118 // Resource busy //#define FS_EFATAL (u32)-119 // fatal error not used by IOS as fatal ERROR +#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time class IWII_IPC_HLE_Device { 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 98a85d25ca..f5a893012a 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 @@ -28,7 +28,7 @@ static Common::replace_v replacements; -// This is used by several of the FileIO and /dev/fs/ functions +// This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size) { std::string path_full = File::GetUserPath(D_WIIROOT_IDX); @@ -128,7 +128,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) // The file must exist before we can open it // It should be created by ISFS_CreateFile, not here - if(File::Exists(m_Filename)) + if (File::Exists(m_Filename)) { INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode); ReturnValue = m_DeviceID; @@ -149,21 +149,22 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) bool CWII_IPC_HLE_Device_FileIO::OpenFile() { - switch(m_Mode) + switch (m_Mode) { case ISFS_OPEN_READ: + { m_pFileHandle.Open(m_Filename, "rb"); break; - - // "r+b" is technically wrong, but OPEN_WRITE should not truncate the file as "wb" does. + } case ISFS_OPEN_WRITE: m_pFileHandle.Open(m_Filename, "r+b"); break; case ISFS_OPEN_RW: + { m_pFileHandle.Open(m_Filename, "r+b"); break; - + } default: PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode); break; @@ -178,21 +179,21 @@ void CWII_IPC_HLE_Device_FileIO::CloseFile() bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) { - u32 ReturnValue = FS_RESULT_FATAL; - const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); - const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); + u32 ReturnValue = FS_RESULT_FATAL; + const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); + const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { ReturnValue = FS_RESULT_FATAL; - const u64 fileSize = m_pFileHandle.GetSize(); + const u64 fileSize = m_pFileHandle.GetSize(); INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize); - switch(Mode){ + switch (Mode){ case 0: { - if(SeekPosition >=0 && SeekPosition <= fileSize) + if (SeekPosition >=0 && SeekPosition <= fileSize) { m_SeekPos = SeekPosition; ReturnValue = m_SeekPos; @@ -202,7 +203,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) case 1: { s32 wantedPos = SeekPosition+m_SeekPos; - if(wantedPos >=0 && wantedPos <= fileSize) + if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; ReturnValue = m_SeekPos; @@ -212,7 +213,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) case 2: { s32 wantedPos = fileSize+m_SeekPos; - if(wantedPos >=0 && wantedPos <= fileSize) + if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; ReturnValue = m_SeekPos; @@ -244,7 +245,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { if (m_Mode == ISFS_OPEN_WRITE) { @@ -284,7 +285,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { if (m_Mode == ISFS_OPEN_READ) { @@ -318,21 +319,14 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) #if defined(_DEBUG) || defined(DEBUGFAST) DumpCommands(_CommandAddress); #endif - const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 ReturnValue = 0; - //u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - //u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - //u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - //u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - - // Return Value - u32 ReturnValue = 0; // no error - - switch(Parameter) + switch (Parameter) { case ISFS_IOCTL_GETFILESTATS: { - if(OpenFile()) + if (OpenFile()) { u32 m_FileLength = (u32)m_pFileHandle.GetSize(); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h index 6c31e7be31..681baeebe6 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -37,7 +37,7 @@ public: virtual bool Close(u32 _CommandAddress, bool _bForce); virtual bool IOCtlV(u32 _CommandAddress); - u32 ES_DIVerify(u8 *_pTMD, u32 _sz); + static u32 ES_DIVerify(u8 *_pTMD, u32 _sz); private: enum