From ab25d1fe9a7e3678b868855eecd402eec2efd1d6 Mon Sep 17 00:00:00 2001 From: Chloe Marcec Date: Tue, 24 Nov 2020 16:40:23 +1100 Subject: [PATCH] nvservices: Reintroducee IoctlCtrl Fixes regression caused by #4907 which caused games like Breath of the Wild 1.0.0 not to boot. --- src/core/hle/service/nvdrv/devices/nvdevice.h | 9 +- .../service/nvdrv/devices/nvdisp_disp0.cpp | 9 +- .../hle/service/nvdrv/devices/nvdisp_disp0.h | 8 +- .../service/nvdrv/devices/nvhost_as_gpu.cpp | 9 +- .../hle/service/nvdrv/devices/nvhost_as_gpu.h | 8 +- .../hle/service/nvdrv/devices/nvhost_ctrl.cpp | 19 ++-- .../hle/service/nvdrv/devices/nvhost_ctrl.h | 11 ++- .../service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 10 ++- .../service/nvdrv/devices/nvhost_ctrl_gpu.h | 8 +- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 8 +- .../hle/service/nvdrv/devices/nvhost_gpu.h | 8 +- .../service/nvdrv/devices/nvhost_nvdec.cpp | 9 +- .../hle/service/nvdrv/devices/nvhost_nvdec.h | 8 +- .../nvdrv/devices/nvhost_nvdec_common.h | 9 +- .../service/nvdrv/devices/nvhost_nvjpg.cpp | 9 +- .../hle/service/nvdrv/devices/nvhost_nvjpg.h | 8 +- .../hle/service/nvdrv/devices/nvhost_vic.cpp | 8 +- .../hle/service/nvdrv/devices/nvhost_vic.h | 8 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 8 +- src/core/hle/service/nvdrv/devices/nvmap.h | 8 +- src/core/hle/service/nvdrv/interface.cpp | 89 +++++++++++++++++-- src/core/hle/service/nvdrv/nvdata.h | 11 +++ src/core/hle/service/nvdrv/nvdrv.cpp | 13 +-- src/core/hle/service/nvdrv/nvdrv.h | 6 +- 24 files changed, 212 insertions(+), 89 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 5681599ba2..44a8bc0604 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -31,8 +31,8 @@ public: * @param output A buffer where the output data will be written to. * @returns The result code of the ioctl. */ - virtual NvResult Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) = 0; + virtual NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) = 0; /** * Handles an ioctl2 request. @@ -43,7 +43,8 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) = 0; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) = 0; /** * Handles an ioctl3 request. @@ -54,7 +55,7 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) = 0; + std::vector& inline_output, IoctlCtrl& ctrl) = 0; protected: Core::System& system; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index ce615c7581..170a7c9a04 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -18,20 +18,21 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr nvmap_de : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} nvdisp_disp0 ::~nvdisp_disp0() = default; -NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) { +NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 55a33b7e47..eb7575e405 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -20,11 +20,13 @@ public: explicit nvdisp_disp0(Core::System& system, std::shared_ptr nvmap_dev); ~nvdisp_disp0() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; /// Performs a screen flip, drawing the buffer pointed to by the handle. void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 6b062e10e3..4e0652c396 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -21,8 +21,8 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr nvmap_ : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} nvhost_as_gpu::~nvhost_as_gpu() = default; -NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) { +NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 'A': switch (command.cmd) { @@ -55,13 +55,14 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector& input, } NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { switch (command.group) { case 'A': switch (command.cmd) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 08035fa0e5..2bd355af96 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -30,11 +30,13 @@ public: explicit nvhost_as_gpu(Core::System& system, std::shared_ptr nvmap_dev); ~nvhost_as_gpu() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; private: class BufferMap final { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index d90cf90a86..92d31b6207 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -20,7 +20,8 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} nvhost_ctrl::~nvhost_ctrl() = default; -NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector& input, std::vector& output) { +NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -29,9 +30,9 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector& input, std::v case 0x1c: return IocCtrlClearEventWait(input, output); case 0x1d: - return IocCtrlEventWait(input, output, false); + return IocCtrlEventWait(input, output, false, ctrl); case 0x1e: - return IocCtrlEventWait(input, output, true); + return IocCtrlEventWait(input, output, true, ctrl); case 0x1f: return IocCtrlEventRegister(input, output); case 0x20: @@ -47,13 +48,14 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector& input, std::v } NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } @@ -67,7 +69,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector& input, std::vector } NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector& output, - bool is_async) { + bool is_async, IoctlCtrl& ctrl) { IocCtrlEventWaitParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", @@ -139,7 +141,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector params.value |= event_id; event.event.writable->Clear(); gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); - if (!is_async) { + if (!is_async && ctrl.fresh_call) { + ctrl.must_delay = true; + ctrl.timeout = params.timeout; + ctrl.event_id = event_id; return NvResult::Timeout; } std::memcpy(output.data(), ¶ms, sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index c5aa1362a5..107168e217 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -18,11 +18,13 @@ public: SyncpointManager& syncpoint_manager); ~nvhost_ctrl() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; private: struct IocSyncptReadParams { @@ -121,7 +123,8 @@ private: static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); NvResult NvOsGetConfigU32(const std::vector& input, std::vector& output); - NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, bool is_async); + NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, bool is_async, + IoctlCtrl& ctrl); NvResult IocCtrlEventRegister(const std::vector& input, std::vector& output); NvResult IocCtrlEventUnregister(const std::vector& input, std::vector& output); NvResult IocCtrlClearEventWait(const std::vector& input, std::vector& output); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 2d7ea433c3..647f5907e7 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -16,7 +16,7 @@ nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) { + std::vector& output, IoctlCtrl& ctrl) { switch (command.group) { case 'G': switch (command.cmd) { @@ -48,13 +48,15 @@ NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector& input, } NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector& input, - std::vector& output, std::vector& inline_output) { + std::vector& output, std::vector& inline_output, + IoctlCtrl& ctrl) { switch (command.group) { case 'G': switch (command.cmd) { @@ -162,7 +164,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector& input, std:: params.gpu_characteristics_buf_size = 0xA0; params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) - std::memcpy(output.data(), input.data(), output.size()); + std::memcpy(output.data(), ¶ms, output.size()); std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 137b882381..c2fffe7349 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -16,11 +16,13 @@ public: explicit nvhost_ctrl_gpu(Core::System& system); ~nvhost_ctrl_gpu() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; private: struct IoctlGpuCharacteristics { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index af8b3d9f15..b0c2caba5f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -23,7 +23,8 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr nvmap_dev, nvhost_gpu::~nvhost_gpu() = default; -NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector& input, std::vector& output) { +NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -75,7 +76,8 @@ NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector& input, std::ve }; NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 'H': switch (command.cmd) { @@ -89,7 +91,7 @@ NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector& input, } NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index e0298b4feb..aa0048a9dc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -26,11 +26,13 @@ public: SyncpointManager& syncpoint_manager); ~nvhost_gpu() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; private: enum class CtxObjects : u32_le { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index d8735491cb..b8328c314d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -15,8 +15,8 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr nvmap_de : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} nvhost_nvdec::~nvhost_nvdec() = default; -NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) { +NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -58,13 +58,14 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector& input, } NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 79b8b6de12..884ed6c5b1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -14,11 +14,13 @@ public: explicit nvhost_nvdec(Core::System& system, std::shared_ptr nvmap_dev); ~nvhost_nvdec() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 86ba3a4d1c..ab152bf0e5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -25,8 +25,8 @@ public: * @param output A buffer where the output data will be written to. * @returns The result code of the ioctl. */ - virtual NvResult Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) = 0; + virtual NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) = 0; /** * Handles an ioctl2 request. @@ -37,7 +37,8 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) = 0; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) = 0; /** * Handles an ioctl3 request. @@ -48,7 +49,7 @@ public: * @returns The result code of the ioctl. */ virtual NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) = 0; + std::vector& inline_output, IoctlCtrl& ctrl) = 0; protected: class BufferMap final { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 2d06955c0f..6f4ab0ab34 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} nvhost_nvjpg::~nvhost_nvjpg() = default; -NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector& input, - std::vector& output) { +NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 'H': switch (command.cmd) { @@ -33,13 +33,14 @@ NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector& input, } NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 43948d18dd..6fb99d959f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -16,11 +16,13 @@ public: explicit nvhost_nvjpg(Core::System& system); ~nvhost_nvjpg() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; private: struct IoctlSetNvmapFD { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 805fe86ae6..55a17f4238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -15,7 +15,8 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr nvmap_dev) nvhost_vic::~nvhost_vic() = default; -NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector& input, std::vector& output) { +NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 0x0: switch (command.cmd) { @@ -50,13 +51,14 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector& input, std::ve } NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index b2e11f4d4b..7f4858cd4c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -14,10 +14,12 @@ public: explicit nvhost_vic(Core::System& system, std::shared_ptr nvmap_dev); ~nvhost_vic(); - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 4015a27400..910cfee512 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -19,7 +19,8 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) { nvmap::~nvmap() = default; -NvResult nvmap::Ioctl1(Ioctl command, const std::vector& input, std::vector& output) { +NvResult nvmap::Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) { switch (command.group) { case 0x1: switch (command.cmd) { @@ -48,13 +49,14 @@ NvResult nvmap::Ioctl1(Ioctl command, const std::vector& input, std::vector< } NvResult nvmap::Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } NvResult nvmap::Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) { + std::vector& inline_output, IoctlCtrl& ctrl) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 4484bd79f3..c0c2fa5ebc 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -19,11 +19,13 @@ public: explicit nvmap(Core::System& system); ~nvmap() override; - NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output) override; + NvResult Ioctl1(Ioctl command, const std::vector& input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl2(Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) override; + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) override; NvResult Ioctl3(Ioctl command, const std::vector& input, std::vector& output, - std::vector& inline_output) override; + std::vector& inline_output, IoctlCtrl& ctrl) override; /// Returns the allocated address of an nvmap object given its handle. VAddr GetObjectAddress(u32 handle) const; diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index f6c38e8530..7bfa5cac91 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -61,10 +61,32 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { std::vector output_buffer(ctx.GetWriteBufferSize(0)); const auto input_buffer = ctx.ReadBuffer(0); - const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); + IoctlCtrl ctrl{}; - if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer); + const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer, ctrl); + if (ctrl.must_delay) { + ctrl.fresh_call = false; + ctx.SleepClientThread( + "NVServices::DelayedResponse", ctrl.timeout, + [=, this](std::shared_ptr thread, Kernel::HLERequestContext& ctx_, + Kernel::ThreadWakeupReason reason) { + IoctlCtrl ctrl2{ctrl}; + std::vector tmp_output = output_buffer; + const auto nv_result2 = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output, ctrl2); + + if (command.is_out != 0) { + ctx.WriteBuffer(tmp_output); + } + + IPC::ResponseBuilder rb{ctx_, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushEnum(nv_result2); + }, + nvdrv->GetEventWriteable(ctrl.event_id)); + } else { + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer); + } } IPC::ResponseBuilder rb{ctx, 3}; @@ -88,8 +110,35 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { const auto input_inlined_buffer = ctx.ReadBuffer(1); std::vector output_buffer(ctx.GetWriteBufferSize(0)); + IoctlCtrl ctrl{}; + const auto nv_result = - nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); + nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer, ctrl); + if (ctrl.must_delay) { + ctrl.fresh_call = false; + ctx.SleepClientThread( + "NVServices::DelayedResponse", ctrl.timeout, + [=, this](std::shared_ptr thread, Kernel::HLERequestContext& ctx_, + Kernel::ThreadWakeupReason reason) { + IoctlCtrl ctrl2{ctrl}; + std::vector tmp_output = output_buffer; + const auto nv_result2 = nvdrv->Ioctl2(fd, command, input_buffer, + input_inlined_buffer, tmp_output, ctrl2); + + if (command.is_out != 0) { + ctx.WriteBuffer(tmp_output); + } + + IPC::ResponseBuilder rb{ctx_, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushEnum(nv_result2); + }, + nvdrv->GetEventWriteable(ctrl.event_id)); + } else { + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer); + } + } if (command.is_out != 0) { ctx.WriteBuffer(output_buffer); @@ -116,12 +165,36 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { std::vector output_buffer(ctx.GetWriteBufferSize(0)); std::vector output_buffer_inline(ctx.GetWriteBufferSize(1)); + IoctlCtrl ctrl{}; const auto nv_result = - nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); + nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline, ctrl); + if (ctrl.must_delay) { + ctrl.fresh_call = false; + ctx.SleepClientThread( + "NVServices::DelayedResponse", ctrl.timeout, + [=, this](std::shared_ptr thread, Kernel::HLERequestContext& ctx_, + Kernel::ThreadWakeupReason reason) { + IoctlCtrl ctrl2{ctrl}; + std::vector tmp_output = output_buffer; + std::vector tmp_output2 = output_buffer; + const auto nv_result2 = + nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output2, ctrl2); - if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer, 0); - ctx.WriteBuffer(output_buffer_inline, 1); + if (command.is_out != 0) { + ctx.WriteBuffer(tmp_output, 0); + ctx.WriteBuffer(tmp_output2, 1); + } + + IPC::ResponseBuilder rb{ctx_, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushEnum(nv_result2); + }, + nvdrv->GetEventWriteable(ctrl.event_id)); + } else { + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer, 0); + ctx.WriteBuffer(output_buffer_inline, 1); + } } IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 3294bc0e70..a3c4ecd853 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -97,4 +97,15 @@ union Ioctl { BitField<31, 1, u32> is_out; }; +struct IoctlCtrl { + // First call done to the servioce for services that call itself again after a call. + bool fresh_call{true}; + // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep + bool must_delay{}; + // Timeout for the delay + s64 timeout{}; + // NV Event Id + s32 event_id{-1}; +}; + } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index bdbbedd0d5..56d927b12f 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -91,7 +91,7 @@ DeviceFD Module::Open(const std::string& device_name) { } NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, - std::vector& output) { + std::vector& output, IoctlCtrl& ctrl) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -104,11 +104,12 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input return NvResult::NotImplemented; } - return itr->second->Ioctl1(command, input, output); + return itr->second->Ioctl1(command, input, output, ctrl); } NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output) { + const std::vector& inline_input, std::vector& output, + IoctlCtrl& ctrl) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -121,11 +122,11 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector& input return NvResult::NotImplemented; } - return itr->second->Ioctl2(command, input, inline_input, output); + return itr->second->Ioctl2(command, input, inline_input, output, ctrl); } NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& input, - std::vector& output, std::vector& inline_output) { + std::vector& output, std::vector& inline_output, IoctlCtrl& ctrl) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -138,7 +139,7 @@ NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& input return NvResult::NotImplemented; } - return itr->second->Ioctl3(command, input, output, inline_output); + return itr->second->Ioctl3(command, input, output, inline_output, ctrl); } NvResult Module::Close(DeviceFD fd) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 7654bb0263..bfffc1e88f 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -119,13 +119,13 @@ public: /// Sends an ioctl command to the specified file descriptor. NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, - std::vector& output); + std::vector& output, IoctlCtrl& ctrl); NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector& input, - const std::vector& inline_input, std::vector& output); + const std::vector& inline_input, std::vector& output, IoctlCtrl& ctrl); NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector& input, - std::vector& output, std::vector& inline_output); + std::vector& output, std::vector& inline_output, IoctlCtrl& ctrl); /// Closes a device file descriptor and returns operation success. NvResult Close(DeviceFD fd);