diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index 8cf9b6fb55..95c9f7a211 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -82,6 +82,9 @@ static int enque_reply; static u64 last_reply_time; +// NOTE: Only call this if you have correctly handled +// CommandAddress+0 and CommandAddress+8. +// Please search for examples of this being called elsewhere. void EnqueReplyCallback(u64 userdata, int) { std::lock_guard lk(s_reply_queue); @@ -347,7 +350,7 @@ void ExecuteCommand(u32 _Address) { bool CmdSuccess = false; - ECommandType Command = static_cast(Memory::Read_U32(_Address)); + IPCCommandType Command = static_cast(Memory::Read_U32(_Address)); volatile s32 DeviceID = Memory::Read_U32(_Address + 8); IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; @@ -356,7 +359,7 @@ void ExecuteCommand(u32 _Address) switch (Command) { - case COMMAND_OPEN_DEVICE: + case IPC_CMD_OPEN: { u32 Mode = Memory::Read_U32(_Address + 0x10); DeviceID = getFreeDeviceId(); @@ -431,7 +434,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_CLOSE_DEVICE: + case IPC_CMD_CLOSE: { if (pDevice) { @@ -461,7 +464,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_READ: + case IPC_CMD_READ: { if (pDevice) { @@ -474,7 +477,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_WRITE: + case IPC_CMD_WRITE: { if (pDevice) { @@ -487,7 +490,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_SEEK: + case IPC_CMD_SEEK: { if (pDevice) { @@ -500,7 +503,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_IOCTL: + case IPC_CMD_IOCTL: { if (pDevice) { @@ -508,7 +511,7 @@ void ExecuteCommand(u32 _Address) } break; } - case COMMAND_IOCTLV: + case IPC_CMD_IOCTLV: { if (pDevice) { @@ -526,10 +529,9 @@ void ExecuteCommand(u32 _Address) if (CmdSuccess) { - // It seems that the original hardware overwrites the command after it has been - // executed. We write 8 which is not any valid command, and what IOS does - Memory::Write_U32(8, _Address); - // IOS seems to write back the command that was responded to + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, _Address); + // IOS also seems to write back the command that was responded to in the FD field. Memory::Write_U32(Command, _Address + 8); // Ensure replies happen in order, fairly ugly @@ -557,6 +559,9 @@ void EnqRequest(u32 _Address) } // Called when IOS module has some reply +// NOTE: Only call this if you have correctly handled +// CommandAddress+0 and CommandAddress+8. +// Please search for examples of this being called elsewhere. void EnqReply(u32 _Address, int cycles_in_future) { CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h index 2bd3983f9d..813c1c0250 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h @@ -8,6 +8,21 @@ class IWII_IPC_HLE_Device; +enum IPCCommandType : u32 +{ + IPC_CMD_OPEN = 1, + IPC_CMD_CLOSE = 2, + IPC_CMD_READ = 3, + IPC_CMD_WRITE = 4, + IPC_CMD_SEEK = 5, + IPC_CMD_IOCTL = 6, + IPC_CMD_IOCTLV = 7, + // IPC_REP_ASYNC is used for messages that are automatically + // sent to an IOS queue when an asynchronous syscall completes. + // Reference: http://wiibrew.org/wiki/IOS + IPC_REP_ASYNC = 8 +}; + namespace WII_IPC_HLE_Interface { @@ -52,15 +67,4 @@ void ExecuteCommand(u32 _Address); void EnqRequest(u32 _Address); void EnqReply(u32 _Address, int cycles_in_future = 0); -enum ECommandType -{ - COMMAND_OPEN_DEVICE = 1, - COMMAND_CLOSE_DEVICE = 2, - COMMAND_READ = 3, - COMMAND_WRITE = 4, - COMMAND_SEEK = 5, - COMMAND_IOCTL = 6, - COMMAND_IOCTLV = 7, -}; - } // end of namespace WII_IPC_HLE_Interface diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 35aad66889..96dc66f03d 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -991,11 +991,10 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) // This is necessary because Reset(true) above deleted this object. Ew. - // It seems that the original hardware overwrites the command after it has been - // executed. We write 8 which is not any valid command, and what IOS does - Memory::Write_U32(8, _CommandAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(7, _CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, _CommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTLV, _CommandAddress + 8); // Generate a reply to the IPC command WII_IPC_HLE_Interface::EnqReply(_CommandAddress, 0); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp index 4e21b99e70..b33c989718 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp @@ -29,9 +29,10 @@ void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid) if (hid->deviceCommandAddress != 0){ hid->FillOutDevices(Memory::Read_U32(hid->deviceCommandAddress + 0x18), Memory::Read_U32(hid->deviceCommandAddress + 0x1C)); - Memory::Write_U32(8, hid->deviceCommandAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(/*COMMAND_IOCTL*/ 6, hid->deviceCommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, hid->deviceCommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, hid->deviceCommandAddress + 8); // Return value Memory::Write_U32(0, hid->deviceCommandAddress + 4); @@ -56,9 +57,10 @@ void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer *transfer) ret = transfer->length; } - Memory::Write_U32(8, replyAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(/*COMMAND_IOCTL*/ 6, replyAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, replyAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, replyAddress + 8); // Return value Memory::Write_U32(ret, replyAddress + 4); @@ -247,9 +249,10 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) if (deviceCommandAddress != 0){ Memory::Write_U32(0xFFFFFFFF, Memory::Read_U32(deviceCommandAddress + 0x18)); - Memory::Write_U32(8, deviceCommandAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(/*COMMAND_IOCTL*/ 6, deviceCommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, deviceCommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, deviceCommandAddress + 8); // Return value Memory::Write_U32(-1, deviceCommandAddress + 4); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp index 89d4af0f41..5eb99b81cc 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp @@ -12,6 +12,18 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h" +void CWII_IPC_HLE_Device_sdio_slot0::EnqueueReply(u32 CommandAddress, u32 ReturnValue) +{ + // IOS seems to write back the command that was responded to, this class does not + // overwrite the command so it is safe to read. + Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + + Memory::Write_U32(ReturnValue, CommandAddress + 4); + + WII_IPC_HLE_Interface::EnqReply(CommandAddress); +} CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) @@ -39,8 +51,7 @@ void CWII_IPC_HLE_Device_sdio_slot0::EventNotify() if ((SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_INSERT) || (!SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_REMOVE)) { - Memory::Write_U32(m_event.type, m_event.addr + 4); - WII_IPC_HLE_Interface::EnqReply(m_event.addr); + EnqueueReply(m_event.addr, m_event.type); m_event.addr = 0; m_event.type = EVENT_NONE; } @@ -222,8 +233,7 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress) // release returns 0 // unknown sd int // technically we do it out of order, oh well - Memory::Write_U32(EVENT_INVALID, m_event.addr + 4); - WII_IPC_HLE_Interface::EnqReply(m_event.addr); + EnqueueReply(m_event.addr, EVENT_INVALID); m_event.addr = 0; m_event.type = EVENT_NONE; Memory::Write_U32(0, _CommandAddress + 0x4); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h index 98afcbd51c..20104b2239 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h @@ -21,6 +21,7 @@ public: bool IOCtl(u32 _CommandAddress) override; bool IOCtlV(u32 _CommandAddress) override; + static void EnqueueReply(u32 CommandAddress, u32 ReturnValue); void EventNotify(); private: diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index df6f797e33..de11fd600c 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -14,6 +14,19 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" + + +void CWII_IPC_HLE_Device_usb_oh1_57e_305::EnqueueReply(u32 CommandAddress) +{ + // IOS seems to write back the command that was responded to in the FD field, this + // class does not overwrite the command so it is safe to read back. + Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + + WII_IPC_HLE_Interface::EnqReply(CommandAddress); +} + // The device class CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) @@ -340,7 +353,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u memcpy((u8*)pHeader + sizeof(hci_acldata_hdr_t), _pData, pHeader->length); m_ACLEndpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + _Size); - WII_IPC_HLE_Interface::EnqReply(m_ACLEndpoint.m_address); + EnqueueReply(m_ACLEndpoint.m_address); m_ACLEndpoint.Invalidate(); } else @@ -367,7 +380,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e m_HCIEndpoint.FillBuffer(_event.m_buffer, _event.m_size); m_HCIEndpoint.SetRetVal(_event.m_size); // Send a reply to indicate HCI buffer is filled - WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_address); m_HCIEndpoint.Invalidate(); } else // push new one, pop oldest @@ -385,7 +398,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); m_HCIEndpoint.SetRetVal(event.m_size); // Send a reply to indicate HCI buffer is filled - WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_address); m_HCIEndpoint.Invalidate(); m_EventQueue.pop_front(); } @@ -415,7 +428,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); m_HCIEndpoint.SetRetVal(event.m_size); // Send a reply to indicate HCI buffer is filled - WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); + EnqueueReply(m_HCIEndpoint.m_address); m_HCIEndpoint.Invalidate(); m_EventQueue.pop_front(); packet_transferred = true; @@ -517,7 +530,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& e m_queue.pop_front(); - WII_IPC_HLE_Interface::EnqReply(endpoint.m_address); + EnqueueReply(endpoint.m_address); endpoint.Invalidate(); } @@ -1214,7 +1227,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom } // HCI command is finished, send a reply to command - WII_IPC_HLE_Interface::EnqReply(_rHCICommandMessage.m_Address); + EnqueueReply(_rHCICommandMessage.m_Address); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h index e2709e9caa..4d42334ade 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h @@ -58,6 +58,8 @@ public: virtual u32 Update() override; + static void EnqueueReply(u32 CommandAddress); + // Send ACL data back to bt stack void SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size); diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.cpp b/Source/Core/Core/IPC_HLE/WII_Socket.cpp index d3a21db739..4a526b20a0 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.cpp +++ b/Source/Core/Core/IPC_HLE/WII_Socket.cpp @@ -8,11 +8,6 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" #include "Core/IPC_HLE/WII_Socket.h" // No Wii socket support while using NetPlay or TAS - -using WII_IPC_HLE_Interface::ECommandType; -using WII_IPC_HLE_Interface::COMMAND_IOCTL; -using WII_IPC_HLE_Interface::COMMAND_IOCTLV; - #ifdef _WIN32 #define ERRORCODE(name) WSA ## name #define EITHER(win32, posix) win32 @@ -180,8 +175,8 @@ void WiiSocket::Update(bool read, bool write, bool except) { s32 ReturnValue = 0; bool forceNonBlock = false; - ECommandType ct = static_cast(Memory::Read_U32(it->_CommandAddress)); - if (!it->is_ssl && ct == COMMAND_IOCTL) + IPCCommandType ct = static_cast(Memory::Read_U32(it->_CommandAddress)); + if (!it->is_ssl && ct == IPC_CMD_IOCTL) { u32 BufferIn = Memory::Read_U32(it->_CommandAddress + 0x10); u32 BufferInSize = Memory::Read_U32(it->_CommandAddress + 0x14); @@ -267,7 +262,7 @@ void WiiSocket::Update(bool read, bool write, bool except) } } } - else if (ct == COMMAND_IOCTLV) + else if (ct == IPC_CMD_IOCTLV) { SIOCtlVBuffer CommandBuffer(it->_CommandAddress); u32 BufferIn = 0, BufferIn2 = 0; @@ -523,7 +518,7 @@ void WiiSocket::Update(bool read, bool write, bool except) DEBUG_LOG(WII_IPC_NET, "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", fd, it->is_ssl ? (int) it->ssl_type : (int) it->net_type, ReturnValue, nonBlock, forceNonBlock); - WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue); + WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue, ct); it = pending_sockops.erase(it); } else @@ -625,11 +620,12 @@ void WiiSockMan::Update() } } -void WiiSockMan::EnqueueReply(u32 CommandAddress, s32 ReturnValue) +void WiiSockMan::EnqueueReply(u32 CommandAddress, s32 ReturnValue, IPCCommandType CommandType) { - Memory::Write_U32(8, CommandAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(CommandType, CommandAddress + 8); // Return value Memory::Write_U32(ReturnValue, CommandAddress + 4); diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.h b/Source/Core/Core/IPC_HLE/WII_Socket.h index 375245f7aa..4fbd3f29e9 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.h +++ b/Source/Core/Core/IPC_HLE/WII_Socket.h @@ -204,7 +204,7 @@ public: return instance; // Instantiated on first use. } void Update(); - static void EnqueueReply(u32 CommandAddress, s32 ReturnValue); + static void EnqueueReply(u32 CommandAddress, s32 ReturnValue, IPCCommandType CommandType); static void Convert(WiiSockAddrIn const & from, sockaddr_in& to); static void Convert(sockaddr_in const & from, WiiSockAddrIn& to, s32 addrlen=-1); // NON-BLOCKING FUNCTIONS @@ -224,10 +224,11 @@ public: { if (WiiSockets.find(sock) == WiiSockets.end()) { + IPCCommandType ct = static_cast(Memory::Read_U32(CommandAddress)); ERROR_LOG(WII_IPC_NET, "DoSock: Error, fd not found (%08x, %08X, %08X)", sock, CommandAddress, type); - EnqueueReply(CommandAddress, -SO_EBADF); + EnqueueReply(CommandAddress, -SO_EBADF, ct); } else {