From 4fea832f49f55e38877fcdb4c4e7092b7c98cb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 29 Nov 2020 00:58:33 +0100 Subject: [PATCH] IOS/NCD: Implement Lock/Unlock more accurately NCD returns an error if it receives a request to lock the driver when it is already locked. Emulating this may seem pointless, but it turns out PPC-side code expects NCD to return an error and will immediately fail and stop initialising wireless stuff if NCD succeeds. --- Source/Core/Core/IOS/Network/NCD/Manage.cpp | 48 ++++++++++++++++++++- Source/Core/Core/IOS/Network/NCD/Manage.h | 3 ++ Source/Core/Core/State.cpp | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/IOS/Network/NCD/Manage.cpp b/Source/Core/Core/IOS/Network/NCD/Manage.cpp index 2fcfb91beb..602a721374 100644 --- a/Source/Core/Core/IOS/Network/NCD/Manage.cpp +++ b/Source/Core/Core/IOS/Network/NCD/Manage.cpp @@ -20,6 +20,12 @@ NetNCDManage::NetNCDManage(Kernel& ios, const std::string& device_name) : Device config.ReadConfig(ios.GetFS().get()); } +void NetNCDManage::DoState(PointerWrap& p) +{ + Device::DoState(p); + p.Do(m_ipc_fd); +} + IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request) { s32 return_value = IPC_SUCCESS; @@ -29,11 +35,51 @@ IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request) switch (request.request) { case IOCTLV_NCD_LOCKWIRELESSDRIVER: + if (!request.HasNumberOfValidVectors(0, 1)) + return GetDefaultReply(IPC_EINVAL); + + if (request.io_vectors[0].size < 2 * sizeof(u32)) + return GetDefaultReply(IPC_EINVAL); + + if (m_ipc_fd != 0) + { + // It is an error to lock the driver again when it is already locked. + common_result = IPC_EINVAL; + } + else + { + // NCD writes the internal address of the request's file descriptor. + // We will just write the value of the file descriptor. + // The value will be positive so this will work fine. + m_ipc_fd = request.fd; + Memory::Write_U32(request.fd, request.io_vectors[0].address + 4); + } break; case IOCTLV_NCD_UNLOCKWIRELESSDRIVER: - // Memory::Read_U32(request.in_vectors.at(0).address); + { + if (!request.HasNumberOfValidVectors(1, 1)) + return GetDefaultReply(IPC_EINVAL); + + if (request.in_vectors[0].size < sizeof(u32)) + return GetDefaultReply(IPC_EINVAL); + + if (request.io_vectors[0].size < sizeof(u32)) + return GetDefaultReply(IPC_EINVAL); + + const u32 request_handle = Memory::Read_U32(request.in_vectors[0].address); + if (m_ipc_fd == request_handle) + { + m_ipc_fd = 0; + common_result = 0; + } + else + { + common_result = -3; + } + break; + } case IOCTLV_NCD_GETCONFIG: INFO_LOG_FMT(IOS_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETCONFIG"); diff --git a/Source/Core/Core/IOS/Network/NCD/Manage.h b/Source/Core/Core/IOS/Network/NCD/Manage.h index 4105bf7408..8da300e719 100644 --- a/Source/Core/Core/IOS/Network/NCD/Manage.h +++ b/Source/Core/Core/IOS/Network/NCD/Manage.h @@ -20,6 +20,8 @@ public: IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; + void DoState(PointerWrap& p) override; + private: enum { @@ -34,5 +36,6 @@ private: }; Net::WiiNetConfig config; + u32 m_ipc_fd = 0; }; } // namespace IOS::HLE::Device diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 823b39c1ba..31802ca471 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 126; // Last changed in PR 9348 +constexpr u32 STATE_VERSION = 127; // Last changed in PR 9300 (temp) // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,