diff options
| author | 2020-11-20 22:15:44 -0800 | |
|---|---|---|
| committer | 2020-11-20 22:15:44 -0800 | |
| commit | afd0e2ee87c0a786e1a21c08689f3b016aa7b83f (patch) | |
| tree | 2ca2468750b9e96eb938473f0b021c938f8f86fb | |
| parent | Merge pull request #4957 from ReinUsesLisp/alpha-test-rt (diff) | |
| parent | Addressed issues (diff) | |
| download | yuzu-afd0e2ee87c0a786e1a21c08689f3b016aa7b83f.tar.gz yuzu-afd0e2ee87c0a786e1a21c08689f3b016aa7b83f.tar.xz yuzu-afd0e2ee87c0a786e1a21c08689f3b016aa7b83f.zip | |
Merge pull request #4907 from ogniK5377/nvdrv-cleanup
core: Make nvservices more standardized
Diffstat (limited to '')
26 files changed, 1220 insertions, 898 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 0240d6643..5681599ba 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -24,25 +24,37 @@ public: | |||
| 24 | explicit nvdevice(Core::System& system) : system{system} {} | 24 | explicit nvdevice(Core::System& system) : system{system} {} |
| 25 | virtual ~nvdevice() = default; | 25 | virtual ~nvdevice() = default; |
| 26 | 26 | ||
| 27 | union Ioctl { | 27 | /** |
| 28 | u32_le raw; | 28 | * Handles an ioctl1 request. |
| 29 | BitField<0, 8, u32> cmd; | 29 | * @param command The ioctl command id. |
| 30 | BitField<8, 8, u32> group; | 30 | * @param input A buffer containing the input data for the ioctl. |
| 31 | BitField<16, 14, u32> length; | 31 | * @param output A buffer where the output data will be written to. |
| 32 | BitField<30, 1, u32> is_in; | 32 | * @returns The result code of the ioctl. |
| 33 | BitField<31, 1, u32> is_out; | 33 | */ |
| 34 | }; | 34 | virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 35 | std::vector<u8>& output) = 0; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Handles an ioctl2 request. | ||
| 39 | * @param command The ioctl command id. | ||
| 40 | * @param input A buffer containing the input data for the ioctl. | ||
| 41 | * @param inline_input A buffer containing the input data for the ioctl which has been inlined. | ||
| 42 | * @param output A buffer where the output data will be written to. | ||
| 43 | * @returns The result code of the ioctl. | ||
| 44 | */ | ||
| 45 | virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 46 | const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; | ||
| 35 | 47 | ||
| 36 | /** | 48 | /** |
| 37 | * Handles an ioctl request. | 49 | * Handles an ioctl3 request. |
| 38 | * @param command The ioctl command id. | 50 | * @param command The ioctl command id. |
| 39 | * @param input A buffer containing the input data for the ioctl. | 51 | * @param input A buffer containing the input data for the ioctl. |
| 40 | * @param output A buffer where the output data will be written to. | 52 | * @param output A buffer where the output data will be written to. |
| 53 | * @param inline_output A buffer where the inlined output data will be written to. | ||
| 41 | * @returns The result code of the ioctl. | 54 | * @returns The result code of the ioctl. |
| 42 | */ | 55 | */ |
| 43 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 56 | virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 44 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 57 | std::vector<u8>& inline_output) = 0; |
| 45 | IoctlVersion version) = 0; | ||
| 46 | 58 | ||
| 47 | protected: | 59 | protected: |
| 48 | Core::System& system; | 60 | 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 3f7b8e670..ce615c758 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; | 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; |
| 20 | 20 | ||
| 21 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | std::vector<u8>& output) { |
| 23 | IoctlVersion version) { | 23 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 24 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 24 | return NvResult::NotImplemented; |
| 25 | return 0; | 25 | } |
| 26 | |||
| 27 | NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 28 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 29 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 30 | return NvResult::NotImplemented; | ||
| 31 | } | ||
| 32 | |||
| 33 | NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 34 | std::vector<u8>& inline_output) { | ||
| 35 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 36 | return NvResult::NotImplemented; | ||
| 26 | } | 37 | } |
| 27 | 38 | ||
| 28 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, | 39 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6fcdeee84..55a33b7e4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -20,9 +20,11 @@ public: | |||
| 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvdisp_disp0() override; | 21 | ~nvdisp_disp0() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 25 | IoctlVersion version) override; | 25 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 26 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 27 | std::vector<u8>& inline_output) override; | ||
| 26 | 28 | ||
| 27 | /// Performs a screen flip, drawing the buffer pointed to by the handle. | 29 | /// Performs a screen flip, drawing the buffer pointed to by the handle. |
| 28 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, | 30 | 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 f2529a12e..6b062e10e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -17,59 +17,77 @@ | |||
| 17 | 17 | ||
| 18 | namespace Service::Nvidia::Devices { | 18 | namespace Service::Nvidia::Devices { |
| 19 | 19 | ||
| 20 | namespace NvErrCodes { | ||
| 21 | constexpr u32 Success{}; | ||
| 22 | constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 23 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 24 | } // namespace NvErrCodes | ||
| 25 | |||
| 26 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 20 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 27 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 21 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 28 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 22 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 29 | 23 | ||
| 30 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 24 | NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 31 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 25 | std::vector<u8>& output) { |
| 32 | IoctlVersion version) { | 26 | switch (command.group) { |
| 33 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 27 | case 'A': |
| 34 | command.raw, input.size(), output.size()); | 28 | switch (command.cmd) { |
| 35 | 29 | case 0x1: | |
| 36 | switch (static_cast<IoctlCommand>(command.raw)) { | 30 | return BindChannel(input, output); |
| 37 | case IoctlCommand::IocInitalizeExCommand: | 31 | case 0x2: |
| 38 | return InitalizeEx(input, output); | 32 | return AllocateSpace(input, output); |
| 39 | case IoctlCommand::IocAllocateSpaceCommand: | 33 | case 0x3: |
| 40 | return AllocateSpace(input, output); | 34 | return FreeSpace(input, output); |
| 41 | case IoctlCommand::IocMapBufferExCommand: | 35 | case 0x5: |
| 42 | return MapBufferEx(input, output); | 36 | return UnmapBuffer(input, output); |
| 43 | case IoctlCommand::IocBindChannelCommand: | 37 | case 0x6: |
| 44 | return BindChannel(input, output); | 38 | return MapBufferEx(input, output); |
| 45 | case IoctlCommand::IocGetVaRegionsCommand: | 39 | case 0x8: |
| 46 | return GetVARegions(input, output); | 40 | return GetVARegions(input, output); |
| 47 | case IoctlCommand::IocUnmapBufferCommand: | 41 | case 0x9: |
| 48 | return UnmapBuffer(input, output); | 42 | return InitalizeEx(input, output); |
| 49 | case IoctlCommand::IocFreeSpaceCommand: | 43 | case 0x14: |
| 50 | return FreeSpace(input, output); | 44 | return Remap(input, output); |
| 45 | default: | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | break; | ||
| 51 | default: | 49 | default: |
| 52 | break; | 50 | break; |
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { | 53 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 56 | return Remap(input, output); | 54 | return NvResult::NotImplemented; |
| 57 | } | 55 | } |
| 56 | |||
| 57 | NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 58 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 60 | return NvResult::NotImplemented; | ||
| 61 | } | ||
| 58 | 62 | ||
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl command"); | 63 | NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 60 | return 0; | 64 | std::vector<u8>& inline_output) { |
| 65 | switch (command.group) { | ||
| 66 | case 'A': | ||
| 67 | switch (command.cmd) { | ||
| 68 | case 0x8: | ||
| 69 | return GetVARegions(input, output, inline_output); | ||
| 70 | default: | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 78 | return NvResult::NotImplemented; | ||
| 61 | } | 79 | } |
| 62 | 80 | ||
| 63 | u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { | 81 | NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 64 | IoctlInitalizeEx params{}; | 82 | IoctlInitalizeEx params{}; |
| 65 | std::memcpy(¶ms, input.data(), input.size()); | 83 | std::memcpy(¶ms, input.data(), input.size()); |
| 66 | 84 | ||
| 67 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 85 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 68 | 86 | ||
| 69 | return 0; | 87 | return NvResult::Success; |
| 70 | } | 88 | } |
| 71 | 89 | ||
| 72 | u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 90 | NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 73 | IoctlAllocSpace params{}; | 91 | IoctlAllocSpace params{}; |
| 74 | std::memcpy(¶ms, input.data(), input.size()); | 92 | std::memcpy(¶ms, input.data(), input.size()); |
| 75 | 93 | ||
| @@ -83,17 +101,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& | |||
| 83 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); | 101 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); |
| 84 | } | 102 | } |
| 85 | 103 | ||
| 86 | auto result{NvErrCodes::Success}; | 104 | auto result = NvResult::Success; |
| 87 | if (!params.offset) { | 105 | if (!params.offset) { |
| 88 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); | 106 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); |
| 89 | result = NvErrCodes::OutOfMemory; | 107 | result = NvResult::InsufficientMemory; |
| 90 | } | 108 | } |
| 91 | 109 | ||
| 92 | std::memcpy(output.data(), ¶ms, output.size()); | 110 | std::memcpy(output.data(), ¶ms, output.size()); |
| 93 | return result; | 111 | return result; |
| 94 | } | 112 | } |
| 95 | 113 | ||
| 96 | u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 114 | NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 97 | IoctlFreeSpace params{}; | 115 | IoctlFreeSpace params{}; |
| 98 | std::memcpy(¶ms, input.data(), input.size()); | 116 | std::memcpy(¶ms, input.data(), input.size()); |
| 99 | 117 | ||
| @@ -104,15 +122,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 104 | static_cast<std::size_t>(params.pages) * params.page_size); | 122 | static_cast<std::size_t>(params.pages) * params.page_size); |
| 105 | 123 | ||
| 106 | std::memcpy(output.data(), ¶ms, output.size()); | 124 | std::memcpy(output.data(), ¶ms, output.size()); |
| 107 | return NvErrCodes::Success; | 125 | return NvResult::Success; |
| 108 | } | 126 | } |
| 109 | 127 | ||
| 110 | u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { | 128 | NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { |
| 111 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); | 129 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); |
| 112 | 130 | ||
| 113 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); | 131 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); |
| 114 | 132 | ||
| 115 | auto result{NvErrCodes::Success}; | 133 | auto result = NvResult::Success; |
| 116 | std::vector<IoctlRemapEntry> entries(num_entries); | 134 | std::vector<IoctlRemapEntry> entries(num_entries); |
| 117 | std::memcpy(entries.data(), input.data(), input.size()); | 135 | std::memcpy(entries.data(), input.data(), input.size()); |
| 118 | 136 | ||
| @@ -123,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 123 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; | 141 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; |
| 124 | if (!object) { | 142 | if (!object) { |
| 125 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); | 143 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); |
| 126 | result = NvErrCodes::InvalidInput; | 144 | result = NvResult::InvalidState; |
| 127 | break; | 145 | break; |
| 128 | } | 146 | } |
| 129 | 147 | ||
| @@ -134,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 134 | 152 | ||
| 135 | if (!addr) { | 153 | if (!addr) { |
| 136 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); | 154 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); |
| 137 | result = NvErrCodes::InvalidInput; | 155 | result = NvResult::InvalidState; |
| 138 | break; | 156 | break; |
| 139 | } | 157 | } |
| 140 | } | 158 | } |
| @@ -143,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 143 | return result; | 161 | return result; |
| 144 | } | 162 | } |
| 145 | 163 | ||
| 146 | u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 147 | IoctlMapBufferEx params{}; | 165 | IoctlMapBufferEx params{}; |
| 148 | std::memcpy(¶ms, input.data(), input.size()); | 166 | std::memcpy(¶ms, input.data(), input.size()); |
| 149 | 167 | ||
| @@ -157,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 157 | if (!object) { | 175 | if (!object) { |
| 158 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); | 176 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); |
| 159 | std::memcpy(output.data(), ¶ms, output.size()); | 177 | std::memcpy(output.data(), ¶ms, output.size()); |
| 160 | return NvErrCodes::InvalidInput; | 178 | return NvResult::InvalidState; |
| 161 | } | 179 | } |
| 162 | 180 | ||
| 163 | // The real nvservices doesn't make a distinction between handles and ids, and | 181 | // The real nvservices doesn't make a distinction between handles and ids, and |
| @@ -184,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 184 | params.mapping_size, params.offset); | 202 | params.mapping_size, params.offset); |
| 185 | 203 | ||
| 186 | std::memcpy(output.data(), ¶ms, output.size()); | 204 | std::memcpy(output.data(), ¶ms, output.size()); |
| 187 | return NvErrCodes::InvalidInput; | 205 | return NvResult::InvalidState; |
| 188 | } | 206 | } |
| 189 | 207 | ||
| 190 | std::memcpy(output.data(), ¶ms, output.size()); | 208 | std::memcpy(output.data(), ¶ms, output.size()); |
| 191 | return NvErrCodes::Success; | 209 | return NvResult::Success; |
| 192 | } else { | 210 | } else { |
| 193 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); | 211 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); |
| 194 | 212 | ||
| 195 | std::memcpy(output.data(), ¶ms, output.size()); | 213 | std::memcpy(output.data(), ¶ms, output.size()); |
| 196 | return NvErrCodes::InvalidInput; | 214 | return NvResult::InvalidState; |
| 197 | } | 215 | } |
| 198 | } | 216 | } |
| 199 | 217 | ||
| @@ -213,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 213 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); | 231 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); |
| 214 | } | 232 | } |
| 215 | 233 | ||
| 216 | auto result{NvErrCodes::Success}; | 234 | auto result = NvResult::Success; |
| 217 | if (!params.offset) { | 235 | if (!params.offset) { |
| 218 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); | 236 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); |
| 219 | result = NvErrCodes::InvalidInput; | 237 | result = NvResult::InvalidState; |
| 220 | } else { | 238 | } else { |
| 221 | AddBufferMap(params.offset, size, physical_address, is_alloc); | 239 | AddBufferMap(params.offset, size, physical_address, is_alloc); |
| 222 | } | 240 | } |
| @@ -225,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 225 | return result; | 243 | return result; |
| 226 | } | 244 | } |
| 227 | 245 | ||
| 228 | u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 246 | NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 229 | IoctlUnmapBuffer params{}; | 247 | IoctlUnmapBuffer params{}; |
| 230 | std::memcpy(¶ms, input.data(), input.size()); | 248 | std::memcpy(¶ms, input.data(), input.size()); |
| 231 | 249 | ||
| @@ -238,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 238 | } | 256 | } |
| 239 | 257 | ||
| 240 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 241 | return NvErrCodes::Success; | 259 | return NvResult::Success; |
| 242 | } | 260 | } |
| 243 | 261 | ||
| 244 | u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { |
| 245 | IoctlBindChannel params{}; | 263 | IoctlBindChannel params{}; |
| 246 | std::memcpy(¶ms, input.data(), input.size()); | 264 | std::memcpy(¶ms, input.data(), input.size()); |
| 247 | 265 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd); | |
| 248 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | ||
| 249 | 266 | ||
| 250 | channel = params.fd; | 267 | channel = params.fd; |
| 251 | return 0; | 268 | return NvResult::Success; |
| 269 | } | ||
| 270 | |||
| 271 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 272 | IoctlGetVaRegions params{}; | ||
| 273 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 274 | |||
| 275 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, | ||
| 276 | params.buf_size); | ||
| 277 | |||
| 278 | params.buf_size = 0x30; | ||
| 279 | params.regions[0].offset = 0x04000000; | ||
| 280 | params.regions[0].page_size = 0x1000; | ||
| 281 | params.regions[0].pages = 0x3fbfff; | ||
| 282 | |||
| 283 | params.regions[1].offset = 0x04000000; | ||
| 284 | params.regions[1].page_size = 0x10000; | ||
| 285 | params.regions[1].pages = 0x1bffff; | ||
| 286 | |||
| 287 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | ||
| 288 | |||
| 289 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 290 | return NvResult::Success; | ||
| 252 | } | 291 | } |
| 253 | 292 | ||
| 254 | u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 294 | std::vector<u8>& inline_output) { | ||
| 255 | IoctlGetVaRegions params{}; | 295 | IoctlGetVaRegions params{}; |
| 256 | std::memcpy(¶ms, input.data(), input.size()); | 296 | std::memcpy(¶ms, input.data(), input.size()); |
| 257 | 297 | ||
| @@ -270,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o | |||
| 270 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | 310 | // TODO(ogniK): This probably can stay stubbed but should add support way way later |
| 271 | 311 | ||
| 272 | std::memcpy(output.data(), ¶ms, output.size()); | 312 | std::memcpy(output.data(), ¶ms, output.size()); |
| 273 | return 0; | 313 | std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size()); |
| 314 | return NvResult::Success; | ||
| 274 | } | 315 | } |
| 275 | 316 | ||
| 276 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { | 317 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { |
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 fcdb40d93..08035fa0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -30,9 +30,11 @@ public: | |||
| 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 31 | ~nvhost_as_gpu() override; | 31 | ~nvhost_as_gpu() override; |
| 32 | 32 | ||
| 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 33 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 34 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 34 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 35 | IoctlVersion version) override; | 35 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 36 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 37 | std::vector<u8>& inline_output) override; | ||
| 36 | 38 | ||
| 37 | private: | 39 | private: |
| 38 | class BufferMap final { | 40 | class BufferMap final { |
| @@ -74,32 +76,21 @@ private: | |||
| 74 | bool is_allocated{}; | 76 | bool is_allocated{}; |
| 75 | }; | 77 | }; |
| 76 | 78 | ||
| 77 | enum class IoctlCommand : u32_le { | ||
| 78 | IocInitalizeExCommand = 0x40284109, | ||
| 79 | IocAllocateSpaceCommand = 0xC0184102, | ||
| 80 | IocRemapCommand = 0x00000014, | ||
| 81 | IocMapBufferExCommand = 0xC0284106, | ||
| 82 | IocBindChannelCommand = 0x40044101, | ||
| 83 | IocGetVaRegionsCommand = 0xC0404108, | ||
| 84 | IocUnmapBufferCommand = 0xC0084105, | ||
| 85 | IocFreeSpaceCommand = 0xC0104103, | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct IoctlInitalizeEx { | 79 | struct IoctlInitalizeEx { |
| 89 | u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default | 80 | u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default |
| 90 | s32_le as_fd; // ignored; passes 0 | 81 | s32_le as_fd{}; // ignored; passes 0 |
| 91 | u32_le flags; // passes 0 | 82 | u32_le flags{}; // passes 0 |
| 92 | u32_le reserved; // ignored; passes 0 | 83 | u32_le reserved{}; // ignored; passes 0 |
| 93 | u64_le unk0; | 84 | u64_le unk0{}; |
| 94 | u64_le unk1; | 85 | u64_le unk1{}; |
| 95 | u64_le unk2; | 86 | u64_le unk2{}; |
| 96 | }; | 87 | }; |
| 97 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); | 88 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); |
| 98 | 89 | ||
| 99 | struct IoctlAllocSpace { | 90 | struct IoctlAllocSpace { |
| 100 | u32_le pages; | 91 | u32_le pages{}; |
| 101 | u32_le page_size; | 92 | u32_le page_size{}; |
| 102 | AddressSpaceFlags flags; | 93 | AddressSpaceFlags flags{}; |
| 103 | INSERT_PADDING_WORDS(1); | 94 | INSERT_PADDING_WORDS(1); |
| 104 | union { | 95 | union { |
| 105 | u64_le offset; | 96 | u64_le offset; |
| @@ -109,70 +100,73 @@ private: | |||
| 109 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); | 100 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); |
| 110 | 101 | ||
| 111 | struct IoctlFreeSpace { | 102 | struct IoctlFreeSpace { |
| 112 | u64_le offset; | 103 | u64_le offset{}; |
| 113 | u32_le pages; | 104 | u32_le pages{}; |
| 114 | u32_le page_size; | 105 | u32_le page_size{}; |
| 115 | }; | 106 | }; |
| 116 | static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); | 107 | static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); |
| 117 | 108 | ||
| 118 | struct IoctlRemapEntry { | 109 | struct IoctlRemapEntry { |
| 119 | u16_le flags; | 110 | u16_le flags{}; |
| 120 | u16_le kind; | 111 | u16_le kind{}; |
| 121 | u32_le nvmap_handle; | 112 | u32_le nvmap_handle{}; |
| 122 | u32_le map_offset; | 113 | u32_le map_offset{}; |
| 123 | u32_le offset; | 114 | u32_le offset{}; |
| 124 | u32_le pages; | 115 | u32_le pages{}; |
| 125 | }; | 116 | }; |
| 126 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); | 117 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); |
| 127 | 118 | ||
| 128 | struct IoctlMapBufferEx { | 119 | struct IoctlMapBufferEx { |
| 129 | AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable | 120 | AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable |
| 130 | u32_le kind; // -1 is default | 121 | u32_le kind{}; // -1 is default |
| 131 | u32_le nvmap_handle; | 122 | u32_le nvmap_handle{}; |
| 132 | u32_le page_size; // 0 means don't care | 123 | u32_le page_size{}; // 0 means don't care |
| 133 | s64_le buffer_offset; | 124 | s64_le buffer_offset{}; |
| 134 | u64_le mapping_size; | 125 | u64_le mapping_size{}; |
| 135 | s64_le offset; | 126 | s64_le offset{}; |
| 136 | }; | 127 | }; |
| 137 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); | 128 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); |
| 138 | 129 | ||
| 139 | struct IoctlUnmapBuffer { | 130 | struct IoctlUnmapBuffer { |
| 140 | s64_le offset; | 131 | s64_le offset{}; |
| 141 | }; | 132 | }; |
| 142 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); | 133 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); |
| 143 | 134 | ||
| 144 | struct IoctlBindChannel { | 135 | struct IoctlBindChannel { |
| 145 | u32_le fd; | 136 | s32_le fd{}; |
| 146 | }; | 137 | }; |
| 147 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); | 138 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); |
| 148 | 139 | ||
| 149 | struct IoctlVaRegion { | 140 | struct IoctlVaRegion { |
| 150 | u64_le offset; | 141 | u64_le offset{}; |
| 151 | u32_le page_size; | 142 | u32_le page_size{}; |
| 152 | INSERT_PADDING_WORDS(1); | 143 | INSERT_PADDING_WORDS(1); |
| 153 | u64_le pages; | 144 | u64_le pages{}; |
| 154 | }; | 145 | }; |
| 155 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); | 146 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); |
| 156 | 147 | ||
| 157 | struct IoctlGetVaRegions { | 148 | struct IoctlGetVaRegions { |
| 158 | u64_le buf_addr; // (contained output user ptr on linux, ignored) | 149 | u64_le buf_addr{}; // (contained output user ptr on linux, ignored) |
| 159 | u32_le buf_size; // forced to 2*sizeof(struct va_region) | 150 | u32_le buf_size{}; // forced to 2*sizeof(struct va_region) |
| 160 | u32_le reserved; | 151 | u32_le reserved{}; |
| 161 | IoctlVaRegion regions[2]; | 152 | IoctlVaRegion regions[2]{}; |
| 162 | }; | 153 | }; |
| 163 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, | 154 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, |
| 164 | "IoctlGetVaRegions is incorrect size"); | 155 | "IoctlGetVaRegions is incorrect size"); |
| 165 | 156 | ||
| 166 | u32 channel{}; | 157 | s32 channel{}; |
| 158 | |||
| 159 | NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 160 | NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 161 | NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 162 | NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 163 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 164 | NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 165 | NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 167 | 166 | ||
| 168 | u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | 167 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); |
| 169 | u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | 168 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 170 | u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); | 169 | std::vector<u8>& inline_output); |
| 171 | u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 172 | u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 173 | u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 174 | u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 175 | u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 176 | 170 | ||
| 177 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | 171 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; |
| 178 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | 172 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 8356a8139..d90cf90a8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, | |||
| 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} | 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} |
| 21 | nvhost_ctrl::~nvhost_ctrl() = default; | 21 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 22 | 22 | ||
| 23 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | switch (command.group) { |
| 25 | IoctlVersion version) { | 25 | case 0x0: |
| 26 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 26 | switch (command.cmd) { |
| 27 | command.raw, input.size(), output.size()); | 27 | case 0x1b: |
| 28 | 28 | return NvOsGetConfigU32(input, output); | |
| 29 | switch (static_cast<IoctlCommand>(command.raw)) { | 29 | case 0x1c: |
| 30 | case IoctlCommand::IocGetConfigCommand: | 30 | return IocCtrlClearEventWait(input, output); |
| 31 | return NvOsGetConfigU32(input, output); | 31 | case 0x1d: |
| 32 | case IoctlCommand::IocCtrlEventWaitCommand: | 32 | return IocCtrlEventWait(input, output, false); |
| 33 | return IocCtrlEventWait(input, output, false, ctrl); | 33 | case 0x1e: |
| 34 | case IoctlCommand::IocCtrlEventWaitAsyncCommand: | 34 | return IocCtrlEventWait(input, output, true); |
| 35 | return IocCtrlEventWait(input, output, true, ctrl); | 35 | case 0x1f: |
| 36 | case IoctlCommand::IocCtrlEventRegisterCommand: | 36 | return IocCtrlEventRegister(input, output); |
| 37 | return IocCtrlEventRegister(input, output); | 37 | case 0x20: |
| 38 | case IoctlCommand::IocCtrlEventUnregisterCommand: | 38 | return IocCtrlEventUnregister(input, output); |
| 39 | return IocCtrlEventUnregister(input, output); | 39 | } |
| 40 | case IoctlCommand::IocCtrlClearEventWaitCommand: | 40 | break; |
| 41 | return IocCtrlClearEventWait(input, output); | ||
| 42 | default: | 41 | default: |
| 43 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 42 | break; |
| 44 | return 0; | ||
| 45 | } | 43 | } |
| 44 | |||
| 45 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 46 | return NvResult::NotImplemented; | ||
| 47 | } | ||
| 48 | |||
| 49 | NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 50 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 51 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 52 | return NvResult::NotImplemented; | ||
| 53 | } | ||
| 54 | |||
| 55 | NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 56 | std::vector<u8>& inline_output) { | ||
| 57 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 58 | return NvResult::NotImplemented; | ||
| 46 | } | 59 | } |
| 47 | 60 | ||
| 48 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { | 61 | NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { |
| 49 | IocGetConfigParams params{}; | 62 | IocGetConfigParams params{}; |
| 50 | std::memcpy(¶ms, input.data(), sizeof(params)); | 63 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 51 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), | 64 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), |
| 52 | params.param_str.data()); | 65 | params.param_str.data()); |
| 53 | return 0x30006; // Returns error on production mode | 66 | return NvResult::ConfigVarNotFound; // Returns error on production mode |
| 54 | } | 67 | } |
| 55 | 68 | ||
| 56 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, | 69 | NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, |
| 57 | bool is_async, IoctlCtrl& ctrl) { | 70 | bool is_async) { |
| 58 | IocCtrlEventWaitParams params{}; | 71 | IocCtrlEventWaitParams params{}; |
| 59 | std::memcpy(¶ms, input.data(), sizeof(params)); | 72 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 60 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", | 73 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", |
| @@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 126 | params.value |= event_id; | 139 | params.value |= event_id; |
| 127 | event.event.writable->Clear(); | 140 | event.event.writable->Clear(); |
| 128 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 141 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 129 | if (!is_async && ctrl.fresh_call) { | 142 | if (!is_async) { |
| 130 | ctrl.must_delay = true; | ||
| 131 | ctrl.timeout = params.timeout; | ||
| 132 | ctrl.event_id = event_id; | ||
| 133 | return NvResult::Timeout; | 143 | return NvResult::Timeout; |
| 134 | } | 144 | } |
| 135 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 145 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| @@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 139 | return NvResult::BadParameter; | 149 | return NvResult::BadParameter; |
| 140 | } | 150 | } |
| 141 | 151 | ||
| 142 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { | 152 | NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { |
| 143 | IocCtrlEventRegisterParams params{}; | 153 | IocCtrlEventRegisterParams params{}; |
| 144 | std::memcpy(¶ms, input.data(), sizeof(params)); | 154 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 145 | const u32 event_id = params.user_event_id & 0x00FF; | 155 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector< | |||
| 154 | return NvResult::Success; | 164 | return NvResult::Success; |
| 155 | } | 165 | } |
| 156 | 166 | ||
| 157 | u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { | 167 | NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, |
| 168 | std::vector<u8>& output) { | ||
| 158 | IocCtrlEventUnregisterParams params{}; | 169 | IocCtrlEventUnregisterParams params{}; |
| 159 | std::memcpy(¶ms, input.data(), sizeof(params)); | 170 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 160 | const u32 event_id = params.user_event_id & 0x00FF; | 171 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto | |||
| 169 | return NvResult::Success; | 180 | return NvResult::Success; |
| 170 | } | 181 | } |
| 171 | 182 | ||
| 172 | u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { | 183 | NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { |
| 173 | IocCtrlEventSignalParams params{}; | 184 | IocCtrlEventSignalParams params{}; |
| 174 | std::memcpy(¶ms, input.data(), sizeof(params)); | 185 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 175 | 186 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 24ad96cb9..c5aa1362a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -18,132 +18,113 @@ public: | |||
| 18 | SyncpointManager& syncpoint_manager); | 18 | SyncpointManager& syncpoint_manager); |
| 19 | ~nvhost_ctrl() override; | 19 | ~nvhost_ctrl() override; |
| 20 | 20 | ||
| 21 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 23 | IoctlVersion version) override; | 23 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 24 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 25 | std::vector<u8>& inline_output) override; | ||
| 24 | 26 | ||
| 25 | private: | 27 | private: |
| 26 | enum class IoctlCommand : u32_le { | ||
| 27 | IocSyncptReadCommand = 0xC0080014, | ||
| 28 | IocSyncptIncrCommand = 0x40040015, | ||
| 29 | IocSyncptWaitCommand = 0xC00C0016, | ||
| 30 | IocModuleMutexCommand = 0x40080017, | ||
| 31 | IocModuleRegRDWRCommand = 0xC0180018, | ||
| 32 | IocSyncptWaitexCommand = 0xC0100019, | ||
| 33 | IocSyncptReadMaxCommand = 0xC008001A, | ||
| 34 | IocGetConfigCommand = 0xC183001B, | ||
| 35 | IocCtrlClearEventWaitCommand = 0xC004001C, | ||
| 36 | IocCtrlEventWaitCommand = 0xC010001D, | ||
| 37 | IocCtrlEventWaitAsyncCommand = 0xC010001E, | ||
| 38 | IocCtrlEventRegisterCommand = 0xC004001F, | ||
| 39 | IocCtrlEventUnregisterCommand = 0xC0040020, | ||
| 40 | IocCtrlEventKillCommand = 0x40080021, | ||
| 41 | }; | ||
| 42 | struct IocSyncptReadParams { | 28 | struct IocSyncptReadParams { |
| 43 | u32_le id; | 29 | u32_le id{}; |
| 44 | u32_le value; | 30 | u32_le value{}; |
| 45 | }; | 31 | }; |
| 46 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); | 32 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); |
| 47 | 33 | ||
| 48 | struct IocSyncptIncrParams { | 34 | struct IocSyncptIncrParams { |
| 49 | u32_le id; | 35 | u32_le id{}; |
| 50 | }; | 36 | }; |
| 51 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); | 37 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); |
| 52 | 38 | ||
| 53 | struct IocSyncptWaitParams { | 39 | struct IocSyncptWaitParams { |
| 54 | u32_le id; | 40 | u32_le id{}; |
| 55 | u32_le thresh; | 41 | u32_le thresh{}; |
| 56 | s32_le timeout; | 42 | s32_le timeout{}; |
| 57 | }; | 43 | }; |
| 58 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); | 44 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); |
| 59 | 45 | ||
| 60 | struct IocModuleMutexParams { | 46 | struct IocModuleMutexParams { |
| 61 | u32_le id; | 47 | u32_le id{}; |
| 62 | u32_le lock; // (0 = unlock and 1 = lock) | 48 | u32_le lock{}; // (0 = unlock and 1 = lock) |
| 63 | }; | 49 | }; |
| 64 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); | 50 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); |
| 65 | 51 | ||
| 66 | struct IocModuleRegRDWRParams { | 52 | struct IocModuleRegRDWRParams { |
| 67 | u32_le id; | 53 | u32_le id{}; |
| 68 | u32_le num_offsets; | 54 | u32_le num_offsets{}; |
| 69 | u32_le block_size; | 55 | u32_le block_size{}; |
| 70 | u32_le offsets; | 56 | u32_le offsets{}; |
| 71 | u32_le values; | 57 | u32_le values{}; |
| 72 | u32_le write; | 58 | u32_le write{}; |
| 73 | }; | 59 | }; |
| 74 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); | 60 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); |
| 75 | 61 | ||
| 76 | struct IocSyncptWaitexParams { | 62 | struct IocSyncptWaitexParams { |
| 77 | u32_le id; | 63 | u32_le id{}; |
| 78 | u32_le thresh; | 64 | u32_le thresh{}; |
| 79 | s32_le timeout; | 65 | s32_le timeout{}; |
| 80 | u32_le value; | 66 | u32_le value{}; |
| 81 | }; | 67 | }; |
| 82 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); | 68 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); |
| 83 | 69 | ||
| 84 | struct IocSyncptReadMaxParams { | 70 | struct IocSyncptReadMaxParams { |
| 85 | u32_le id; | 71 | u32_le id{}; |
| 86 | u32_le value; | 72 | u32_le value{}; |
| 87 | }; | 73 | }; |
| 88 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); | 74 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); |
| 89 | 75 | ||
| 90 | struct IocGetConfigParams { | 76 | struct IocGetConfigParams { |
| 91 | std::array<char, 0x41> domain_str; | 77 | std::array<char, 0x41> domain_str{}; |
| 92 | std::array<char, 0x41> param_str; | 78 | std::array<char, 0x41> param_str{}; |
| 93 | std::array<char, 0x101> config_str; | 79 | std::array<char, 0x101> config_str{}; |
| 94 | }; | 80 | }; |
| 95 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); | 81 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); |
| 96 | 82 | ||
| 97 | struct IocCtrlEventSignalParams { | 83 | struct IocCtrlEventSignalParams { |
| 98 | u32_le event_id; | 84 | u32_le event_id{}; |
| 99 | }; | 85 | }; |
| 100 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, | 86 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, |
| 101 | "IocCtrlEventSignalParams is incorrect size"); | 87 | "IocCtrlEventSignalParams is incorrect size"); |
| 102 | 88 | ||
| 103 | struct IocCtrlEventWaitParams { | 89 | struct IocCtrlEventWaitParams { |
| 104 | u32_le syncpt_id; | 90 | u32_le syncpt_id{}; |
| 105 | u32_le threshold; | 91 | u32_le threshold{}; |
| 106 | s32_le timeout; | 92 | s32_le timeout{}; |
| 107 | u32_le value; | 93 | u32_le value{}; |
| 108 | }; | 94 | }; |
| 109 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); | 95 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); |
| 110 | 96 | ||
| 111 | struct IocCtrlEventWaitAsyncParams { | 97 | struct IocCtrlEventWaitAsyncParams { |
| 112 | u32_le syncpt_id; | 98 | u32_le syncpt_id{}; |
| 113 | u32_le threshold; | 99 | u32_le threshold{}; |
| 114 | u32_le timeout; | 100 | u32_le timeout{}; |
| 115 | u32_le value; | 101 | u32_le value{}; |
| 116 | }; | 102 | }; |
| 117 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, | 103 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, |
| 118 | "IocCtrlEventWaitAsyncParams is incorrect size"); | 104 | "IocCtrlEventWaitAsyncParams is incorrect size"); |
| 119 | 105 | ||
| 120 | struct IocCtrlEventRegisterParams { | 106 | struct IocCtrlEventRegisterParams { |
| 121 | u32_le user_event_id; | 107 | u32_le user_event_id{}; |
| 122 | }; | 108 | }; |
| 123 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, | 109 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, |
| 124 | "IocCtrlEventRegisterParams is incorrect size"); | 110 | "IocCtrlEventRegisterParams is incorrect size"); |
| 125 | 111 | ||
| 126 | struct IocCtrlEventUnregisterParams { | 112 | struct IocCtrlEventUnregisterParams { |
| 127 | u32_le user_event_id; | 113 | u32_le user_event_id{}; |
| 128 | }; | 114 | }; |
| 129 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, | 115 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, |
| 130 | "IocCtrlEventUnregisterParams is incorrect size"); | 116 | "IocCtrlEventUnregisterParams is incorrect size"); |
| 131 | 117 | ||
| 132 | struct IocCtrlEventKill { | 118 | struct IocCtrlEventKill { |
| 133 | u64_le user_events; | 119 | u64_le user_events{}; |
| 134 | }; | 120 | }; |
| 135 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); | 121 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); |
| 136 | 122 | ||
| 137 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); |
| 138 | 124 | NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); | |
| 139 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, | 125 | NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); |
| 140 | IoctlCtrl& ctrl); | 126 | NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); |
| 141 | 127 | NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | |
| 142 | u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 143 | |||
| 144 | u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 145 | |||
| 146 | u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 147 | 128 | ||
| 148 | EventInterface& events_interface; | 129 | EventInterface& events_interface; |
| 149 | SyncpointManager& syncpoint_manager; | 130 | SyncpointManager& syncpoint_manager; |
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 fba89e7a6..2d7ea433c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices { | |||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} |
| 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, | 18 | NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 19 | const std::vector<u8>& input2, std::vector<u8>& output, | 19 | std::vector<u8>& output) { |
| 20 | std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { | 20 | switch (command.group) { |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | case 'G': |
| 22 | command.raw, input.size(), output.size()); | 22 | switch (command.cmd) { |
| 23 | 23 | case 0x1: | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | return ZCullGetCtxSize(input, output); |
| 25 | case IoctlCommand::IocGetCharacteristicsCommand: | 25 | case 0x2: |
| 26 | return GetCharacteristics(input, output, output2, version); | 26 | return ZCullGetInfo(input, output); |
| 27 | case IoctlCommand::IocGetTPCMasksCommand: | 27 | case 0x3: |
| 28 | return GetTPCMasks(input, output, output2, version); | 28 | return ZBCSetTable(input, output); |
| 29 | case IoctlCommand::IocGetActiveSlotMaskCommand: | 29 | case 0x4: |
| 30 | return GetActiveSlotMask(input, output); | 30 | return ZBCQueryTable(input, output); |
| 31 | case IoctlCommand::IocZcullGetCtxSizeCommand: | 31 | case 0x5: |
| 32 | return ZCullGetCtxSize(input, output); | 32 | return GetCharacteristics(input, output); |
| 33 | case IoctlCommand::IocZcullGetInfo: | 33 | case 0x6: |
| 34 | return ZCullGetInfo(input, output); | 34 | return GetTPCMasks(input, output); |
| 35 | case IoctlCommand::IocZbcSetTable: | 35 | case 0x7: |
| 36 | return ZBCSetTable(input, output); | 36 | return FlushL2(input, output); |
| 37 | case IoctlCommand::IocZbcQueryTable: | 37 | case 0x14: |
| 38 | return ZBCQueryTable(input, output); | 38 | return GetActiveSlotMask(input, output); |
| 39 | case IoctlCommand::IocFlushL2: | 39 | case 0x1c: |
| 40 | return FlushL2(input, output); | 40 | return GetGpuTime(input, output); |
| 41 | case IoctlCommand::IocGetGpuTime: | 41 | default: |
| 42 | return GetGpuTime(input, output); | 42 | break; |
| 43 | } | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, | ||
| 57 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 58 | switch (command.group) { | ||
| 59 | case 'G': | ||
| 60 | switch (command.cmd) { | ||
| 61 | case 0x5: | ||
| 62 | return GetCharacteristics(input, output, inline_output); | ||
| 63 | case 0x6: | ||
| 64 | return GetTPCMasks(input, output, inline_output); | ||
| 65 | default: | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | break; | ||
| 43 | default: | 69 | default: |
| 44 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 70 | break; |
| 45 | return 0; | ||
| 46 | } | 71 | } |
| 72 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 73 | return NvResult::NotImplemented; | ||
| 47 | } | 74 | } |
| 48 | 75 | ||
| 49 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 76 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, |
| 50 | std::vector<u8>& output2, IoctlVersion version) { | 77 | std::vector<u8>& output) { |
| 51 | LOG_DEBUG(Service_NVDRV, "called"); | 78 | LOG_DEBUG(Service_NVDRV, "called"); |
| 52 | IoctlCharacteristics params{}; | 79 | IoctlCharacteristics params{}; |
| 53 | std::memcpy(¶ms, input.data(), input.size()); | 80 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto | |||
| 88 | params.gc.gr_compbit_store_base_hw = 0x0; | 115 | params.gc.gr_compbit_store_base_hw = 0x0; |
| 89 | params.gpu_characteristics_buf_size = 0xA0; | 116 | params.gpu_characteristics_buf_size = 0xA0; |
| 90 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | 117 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) |
| 118 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 119 | return NvResult::Success; | ||
| 120 | } | ||
| 91 | 121 | ||
| 92 | if (version == IoctlVersion::Version3) { | 122 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 93 | std::memcpy(output.data(), input.data(), output.size()); | 123 | std::vector<u8>& inline_output) { |
| 94 | std::memcpy(output2.data(), ¶ms.gc, output2.size()); | 124 | LOG_DEBUG(Service_NVDRV, "called"); |
| 95 | } else { | 125 | IoctlCharacteristics params{}; |
| 96 | std::memcpy(output.data(), ¶ms, output.size()); | 126 | std::memcpy(¶ms, input.data(), input.size()); |
| 97 | } | 127 | params.gc.arch = 0x120; |
| 98 | return 0; | 128 | params.gc.impl = 0xb; |
| 129 | params.gc.rev = 0xa1; | ||
| 130 | params.gc.num_gpc = 0x1; | ||
| 131 | params.gc.l2_cache_size = 0x40000; | ||
| 132 | params.gc.on_board_video_memory_size = 0x0; | ||
| 133 | params.gc.num_tpc_per_gpc = 0x2; | ||
| 134 | params.gc.bus_type = 0x20; | ||
| 135 | params.gc.big_page_size = 0x20000; | ||
| 136 | params.gc.compression_page_size = 0x20000; | ||
| 137 | params.gc.pde_coverage_bit_count = 0x1B; | ||
| 138 | params.gc.available_big_page_sizes = 0x30000; | ||
| 139 | params.gc.gpc_mask = 0x1; | ||
| 140 | params.gc.sm_arch_sm_version = 0x503; | ||
| 141 | params.gc.sm_arch_spa_version = 0x503; | ||
| 142 | params.gc.sm_arch_warp_count = 0x80; | ||
| 143 | params.gc.gpu_va_bit_count = 0x28; | ||
| 144 | params.gc.reserved = 0x0; | ||
| 145 | params.gc.flags = 0x55; | ||
| 146 | params.gc.twod_class = 0x902D; | ||
| 147 | params.gc.threed_class = 0xB197; | ||
| 148 | params.gc.compute_class = 0xB1C0; | ||
| 149 | params.gc.gpfifo_class = 0xB06F; | ||
| 150 | params.gc.inline_to_memory_class = 0xA140; | ||
| 151 | params.gc.dma_copy_class = 0xB0B5; | ||
| 152 | params.gc.max_fbps_count = 0x1; | ||
| 153 | params.gc.fbp_en_mask = 0x0; | ||
| 154 | params.gc.max_ltc_per_fbp = 0x2; | ||
| 155 | params.gc.max_lts_per_ltc = 0x1; | ||
| 156 | params.gc.max_tex_per_tpc = 0x0; | ||
| 157 | params.gc.max_gpc_count = 0x1; | ||
| 158 | params.gc.rop_l2_en_mask_0 = 0x21D70; | ||
| 159 | params.gc.rop_l2_en_mask_1 = 0x0; | ||
| 160 | params.gc.chipname = 0x6230326D67; | ||
| 161 | params.gc.gr_compbit_store_base_hw = 0x0; | ||
| 162 | params.gpu_characteristics_buf_size = 0xA0; | ||
| 163 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | ||
| 164 | |||
| 165 | std::memcpy(output.data(), input.data(), output.size()); | ||
| 166 | std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); | ||
| 167 | return NvResult::Success; | ||
| 99 | } | 168 | } |
| 100 | 169 | ||
| 101 | u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, | 170 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { |
| 102 | std::vector<u8>& output2, IoctlVersion version) { | ||
| 103 | IoctlGpuGetTpcMasksArgs params{}; | 171 | IoctlGpuGetTpcMasksArgs params{}; |
| 104 | std::memcpy(¶ms, input.data(), input.size()); | 172 | std::memcpy(¶ms, input.data(), input.size()); |
| 105 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); | 173 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 106 | if (params.mask_buffer_size != 0) { | 174 | if (params.mask_buffer_size != 0) { |
| 107 | params.tcp_mask = 3; | 175 | params.tcp_mask = 3; |
| 108 | } | 176 | } |
| 177 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 178 | return NvResult::Success; | ||
| 179 | } | ||
| 109 | 180 | ||
| 110 | if (version == IoctlVersion::Version3) { | 181 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 111 | std::memcpy(output.data(), input.data(), output.size()); | 182 | std::vector<u8>& inline_output) { |
| 112 | std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size()); | 183 | IoctlGpuGetTpcMasksArgs params{}; |
| 113 | } else { | 184 | std::memcpy(¶ms, input.data(), input.size()); |
| 114 | std::memcpy(output.data(), ¶ms, output.size()); | 185 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 186 | if (params.mask_buffer_size != 0) { | ||
| 187 | params.tcp_mask = 3; | ||
| 115 | } | 188 | } |
| 116 | 189 | std::memcpy(output.data(), ¶ms, output.size()); | |
| 117 | return 0; | 190 | std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); |
| 191 | return NvResult::Success; | ||
| 118 | } | 192 | } |
| 119 | 193 | ||
| 120 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 194 | NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 121 | LOG_DEBUG(Service_NVDRV, "called"); | 195 | LOG_DEBUG(Service_NVDRV, "called"); |
| 122 | 196 | ||
| 123 | IoctlActiveSlotMask params{}; | 197 | IoctlActiveSlotMask params{}; |
| @@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 127 | params.slot = 0x07; | 201 | params.slot = 0x07; |
| 128 | params.mask = 0x01; | 202 | params.mask = 0x01; |
| 129 | std::memcpy(output.data(), ¶ms, output.size()); | 203 | std::memcpy(output.data(), ¶ms, output.size()); |
| 130 | return 0; | 204 | return NvResult::Success; |
| 131 | } | 205 | } |
| 132 | 206 | ||
| 133 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 207 | NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 134 | LOG_DEBUG(Service_NVDRV, "called"); | 208 | LOG_DEBUG(Service_NVDRV, "called"); |
| 135 | 209 | ||
| 136 | IoctlZcullGetCtxSize params{}; | 210 | IoctlZcullGetCtxSize params{}; |
| @@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 139 | } | 213 | } |
| 140 | params.size = 0x1; | 214 | params.size = 0x1; |
| 141 | std::memcpy(output.data(), ¶ms, output.size()); | 215 | std::memcpy(output.data(), ¶ms, output.size()); |
| 142 | return 0; | 216 | return NvResult::Success; |
| 143 | } | 217 | } |
| 144 | 218 | ||
| 145 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 219 | NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | LOG_DEBUG(Service_NVDRV, "called"); | 220 | LOG_DEBUG(Service_NVDRV, "called"); |
| 147 | 221 | ||
| 148 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 222 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| @@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 162 | params.subregion_height_align_pixels = 0x40; | 236 | params.subregion_height_align_pixels = 0x40; |
| 163 | params.subregion_count = 0x10; | 237 | params.subregion_count = 0x10; |
| 164 | std::memcpy(output.data(), ¶ms, output.size()); | 238 | std::memcpy(output.data(), ¶ms, output.size()); |
| 165 | return 0; | 239 | return NvResult::Success; |
| 166 | } | 240 | } |
| 167 | 241 | ||
| 168 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 242 | NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 169 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 243 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 170 | 244 | ||
| 171 | IoctlZbcSetTable params{}; | 245 | IoctlZbcSetTable params{}; |
| 172 | std::memcpy(¶ms, input.data(), input.size()); | 246 | std::memcpy(¶ms, input.data(), input.size()); |
| 173 | // TODO(ogniK): What does this even actually do? | 247 | // TODO(ogniK): What does this even actually do? |
| 174 | std::memcpy(output.data(), ¶ms, output.size()); | 248 | std::memcpy(output.data(), ¶ms, output.size()); |
| 175 | return 0; | 249 | return NvResult::Success; |
| 176 | } | 250 | } |
| 177 | 251 | ||
| 178 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 252 | NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 179 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 253 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 180 | 254 | ||
| 181 | IoctlZbcQueryTable params{}; | 255 | IoctlZbcQueryTable params{}; |
| 182 | std::memcpy(¶ms, input.data(), input.size()); | 256 | std::memcpy(¶ms, input.data(), input.size()); |
| 183 | // TODO : To implement properly | 257 | // TODO : To implement properly |
| 184 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 185 | return 0; | 259 | return NvResult::Success; |
| 186 | } | 260 | } |
| 187 | 261 | ||
| 188 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 189 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 263 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 190 | 264 | ||
| 191 | IoctlFlushL2 params{}; | 265 | IoctlFlushL2 params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 266 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | // TODO : To implement properly | 267 | // TODO : To implement properly |
| 194 | std::memcpy(output.data(), ¶ms, output.size()); | 268 | std::memcpy(output.data(), ¶ms, output.size()); |
| 195 | return 0; | 269 | return NvResult::Success; |
| 196 | } | 270 | } |
| 197 | 271 | ||
| 198 | u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { | 272 | NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { |
| 199 | LOG_DEBUG(Service_NVDRV, "called"); | 273 | LOG_DEBUG(Service_NVDRV, "called"); |
| 200 | 274 | ||
| 201 | IoctlGetGpuTime params{}; | 275 | IoctlGetGpuTime params{}; |
| 202 | std::memcpy(¶ms, input.data(), input.size()); | 276 | std::memcpy(¶ms, input.data(), input.size()); |
| 203 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); | 277 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); |
| 204 | std::memcpy(output.data(), ¶ms, output.size()); | 278 | std::memcpy(output.data(), ¶ms, output.size()); |
| 205 | return 0; | 279 | return NvResult::Success; |
| 206 | } | 280 | } |
| 207 | 281 | ||
| 208 | } // namespace Service::Nvidia::Devices | 282 | } // namespace Service::Nvidia::Devices |
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 ef60f72ce..137b88238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -16,32 +16,13 @@ public: | |||
| 16 | explicit nvhost_ctrl_gpu(Core::System& system); | 16 | explicit nvhost_ctrl_gpu(Core::System& system); |
| 17 | ~nvhost_ctrl_gpu() override; | 17 | ~nvhost_ctrl_gpu() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocGetCharacteristicsCommand = 0xC0B04705, | ||
| 26 | IocGetTPCMasksCommand = 0xC0184706, | ||
| 27 | IocGetActiveSlotMaskCommand = 0x80084714, | ||
| 28 | IocZcullGetCtxSizeCommand = 0x80044701, | ||
| 29 | IocZcullGetInfo = 0x80284702, | ||
| 30 | IocZbcSetTable = 0x402C4703, | ||
| 31 | IocZbcQueryTable = 0xC0344704, | ||
| 32 | IocFlushL2 = 0x40084707, | ||
| 33 | IocInvalICache = 0x4008470D, | ||
| 34 | IocSetMmudebugMode = 0x4008470E, | ||
| 35 | IocSetSmDebugMode = 0x4010470F, | ||
| 36 | IocWaitForPause = 0xC0084710, | ||
| 37 | IocGetTcpExceptionEnStatus = 0x80084711, | ||
| 38 | IocNumVsms = 0x80084712, | ||
| 39 | IocVsmsMapping = 0xC0044713, | ||
| 40 | IocGetErrorChannelUserData = 0xC008471B, | ||
| 41 | IocGetGpuTime = 0xC010471C, | ||
| 42 | IocGetCpuTimeCorrelationInfo = 0xC108471D, | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct IoctlGpuCharacteristics { | 26 | struct IoctlGpuCharacteristics { |
| 46 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) | 27 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) |
| 47 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) | 28 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) |
| @@ -159,17 +140,21 @@ private: | |||
| 159 | }; | 140 | }; |
| 160 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); | 141 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); |
| 161 | 142 | ||
| 162 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 143 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); |
| 163 | std::vector<u8>& output2, IoctlVersion version); | 144 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 164 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, | 145 | std::vector<u8>& inline_output); |
| 165 | IoctlVersion version); | 146 | |
| 166 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 147 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 167 | u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); | 148 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 168 | u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); | 149 | std::vector<u8>& inline_output); |
| 169 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | 150 | |
| 170 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | 151 | NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| 171 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | 152 | NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); |
| 172 | u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | 153 | NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); |
| 154 | NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 155 | NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 156 | NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 157 | NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 173 | }; | 158 | }; |
| 174 | 159 | ||
| 175 | } // namespace Service::Nvidia::Devices | 160 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b1d9d55b5..af8b3d9f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | |||
| 23 | 23 | ||
| 24 | nvhost_gpu::~nvhost_gpu() = default; | 24 | nvhost_gpu::~nvhost_gpu() = default; |
| 25 | 25 | ||
| 26 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 26 | NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 27 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 27 | switch (command.group) { |
| 28 | IoctlVersion version) { | 28 | case 0x0: |
| 29 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 29 | switch (command.cmd) { |
| 30 | command.raw, input.size(), output.size()); | 30 | case 0x3: |
| 31 | 31 | return GetWaitbase(input, output); | |
| 32 | switch (static_cast<IoctlCommand>(command.raw)) { | 32 | default: |
| 33 | case IoctlCommand::IocSetNVMAPfdCommand: | 33 | break; |
| 34 | return SetNVMAPfd(input, output); | 34 | } |
| 35 | case IoctlCommand::IocSetClientDataCommand: | 35 | break; |
| 36 | return SetClientData(input, output); | 36 | case 'H': |
| 37 | case IoctlCommand::IocGetClientDataCommand: | 37 | switch (command.cmd) { |
| 38 | return GetClientData(input, output); | 38 | case 0x1: |
| 39 | case IoctlCommand::IocZCullBind: | 39 | return SetNVMAPfd(input, output); |
| 40 | return ZCullBind(input, output); | 40 | case 0x3: |
| 41 | case IoctlCommand::IocSetErrorNotifierCommand: | 41 | return ChannelSetTimeout(input, output); |
| 42 | return SetErrorNotifier(input, output); | 42 | case 0x8: |
| 43 | case IoctlCommand::IocChannelSetPriorityCommand: | 43 | return SubmitGPFIFOBase(input, output, false); |
| 44 | return SetChannelPriority(input, output); | 44 | case 0x9: |
| 45 | case IoctlCommand::IocAllocGPFIFOEx2Command: | 45 | return AllocateObjectContext(input, output); |
| 46 | return AllocGPFIFOEx2(input, output); | 46 | case 0xb: |
| 47 | case IoctlCommand::IocAllocObjCtxCommand: | 47 | return ZCullBind(input, output); |
| 48 | return AllocateObjectContext(input, output); | 48 | case 0xc: |
| 49 | case IoctlCommand::IocChannelGetWaitbaseCommand: | 49 | return SetErrorNotifier(input, output); |
| 50 | return GetWaitbase(input, output); | 50 | case 0xd: |
| 51 | case IoctlCommand::IocChannelSetTimeoutCommand: | 51 | return SetChannelPriority(input, output); |
| 52 | return ChannelSetTimeout(input, output); | 52 | case 0x1a: |
| 53 | case IoctlCommand::IocChannelSetTimeslice: | 53 | return AllocGPFIFOEx2(input, output); |
| 54 | return ChannelSetTimeslice(input, output); | 54 | case 0x1b: |
| 55 | default: | 55 | return SubmitGPFIFOBase(input, output, true); |
| 56 | case 0x1d: | ||
| 57 | return ChannelSetTimeslice(input, output); | ||
| 58 | default: | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | break; | ||
| 62 | case 'G': | ||
| 63 | switch (command.cmd) { | ||
| 64 | case 0x14: | ||
| 65 | return SetClientData(input, output); | ||
| 66 | case 0x15: | ||
| 67 | return GetClientData(input, output); | ||
| 68 | default: | ||
| 69 | break; | ||
| 70 | } | ||
| 56 | break; | 71 | break; |
| 57 | } | 72 | } |
| 73 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 74 | return NvResult::NotImplemented; | ||
| 75 | }; | ||
| 58 | 76 | ||
| 59 | if (command.group == NVGPU_IOCTL_MAGIC) { | 77 | NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 60 | if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { | 78 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 61 | return SubmitGPFIFO(input, output); | 79 | switch (command.group) { |
| 62 | } | 80 | case 'H': |
| 63 | if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { | 81 | switch (command.cmd) { |
| 64 | return KickoffPB(input, output, input2, version); | 82 | case 0x1b: |
| 83 | return SubmitGPFIFOBase(input, inline_input, output); | ||
| 65 | } | 84 | } |
| 85 | break; | ||
| 66 | } | 86 | } |
| 87 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 88 | return NvResult::NotImplemented; | ||
| 89 | } | ||
| 67 | 90 | ||
| 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 91 | NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 69 | return 0; | 92 | std::vector<u8>& inline_output) { |
| 70 | }; | 93 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 94 | return NvResult::NotImplemented; | ||
| 95 | } | ||
| 71 | 96 | ||
| 72 | u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 97 | NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { |
| 73 | IoctlSetNvmapFD params{}; | 98 | IoctlSetNvmapFD params{}; |
| 74 | std::memcpy(¶ms, input.data(), input.size()); | 99 | std::memcpy(¶ms, input.data(), input.size()); |
| 75 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 100 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 76 | 101 | ||
| 77 | nvmap_fd = params.nvmap_fd; | 102 | nvmap_fd = params.nvmap_fd; |
| 78 | return 0; | 103 | return NvResult::Success; |
| 79 | } | 104 | } |
| 80 | 105 | ||
| 81 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 106 | NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 82 | LOG_DEBUG(Service_NVDRV, "called"); | 107 | LOG_DEBUG(Service_NVDRV, "called"); |
| 83 | 108 | ||
| 84 | IoctlClientData params{}; | 109 | IoctlClientData params{}; |
| 85 | std::memcpy(¶ms, input.data(), input.size()); | 110 | std::memcpy(¶ms, input.data(), input.size()); |
| 86 | user_data = params.data; | 111 | user_data = params.data; |
| 87 | return 0; | 112 | return NvResult::Success; |
| 88 | } | 113 | } |
| 89 | 114 | ||
| 90 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 115 | NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 91 | LOG_DEBUG(Service_NVDRV, "called"); | 116 | LOG_DEBUG(Service_NVDRV, "called"); |
| 92 | 117 | ||
| 93 | IoctlClientData params{}; | 118 | IoctlClientData params{}; |
| 94 | std::memcpy(¶ms, input.data(), input.size()); | 119 | std::memcpy(¶ms, input.data(), input.size()); |
| 95 | params.data = user_data; | 120 | params.data = user_data; |
| 96 | std::memcpy(output.data(), ¶ms, output.size()); | 121 | std::memcpy(output.data(), ¶ms, output.size()); |
| 97 | return 0; | 122 | return NvResult::Success; |
| 98 | } | 123 | } |
| 99 | 124 | ||
| 100 | u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { | 125 | NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { |
| 101 | std::memcpy(&zcull_params, input.data(), input.size()); | 126 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 102 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 127 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 103 | zcull_params.mode); | 128 | zcull_params.mode); |
| 104 | 129 | ||
| 105 | std::memcpy(output.data(), &zcull_params, output.size()); | 130 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 106 | return 0; | 131 | return NvResult::Success; |
| 107 | } | 132 | } |
| 108 | 133 | ||
| 109 | u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { | 134 | NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { |
| 110 | IoctlSetErrorNotifier params{}; | 135 | IoctlSetErrorNotifier params{}; |
| 111 | std::memcpy(¶ms, input.data(), input.size()); | 136 | std::memcpy(¶ms, input.data(), input.size()); |
| 112 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 137 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 113 | params.size, params.mem); | 138 | params.size, params.mem); |
| 114 | 139 | ||
| 115 | std::memcpy(output.data(), ¶ms, output.size()); | 140 | std::memcpy(output.data(), ¶ms, output.size()); |
| 116 | return 0; | 141 | return NvResult::Success; |
| 117 | } | 142 | } |
| 118 | 143 | ||
| 119 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 144 | NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 120 | std::memcpy(&channel_priority, input.data(), input.size()); | 145 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 121 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 146 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 122 | 147 | ||
| 123 | return 0; | 148 | return NvResult::Success; |
| 124 | } | 149 | } |
| 125 | 150 | ||
| 126 | u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { | 151 | NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 127 | IoctlAllocGpfifoEx2 params{}; | 152 | IoctlAllocGpfifoEx2 params{}; |
| 128 | std::memcpy(¶ms, input.data(), input.size()); | 153 | std::memcpy(¶ms, input.data(), input.size()); |
| 129 | LOG_WARNING(Service_NVDRV, | 154 | LOG_WARNING(Service_NVDRV, |
| @@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 137 | params.fence_out = channel_fence; | 162 | params.fence_out = channel_fence; |
| 138 | 163 | ||
| 139 | std::memcpy(output.data(), ¶ms, output.size()); | 164 | std::memcpy(output.data(), ¶ms, output.size()); |
| 140 | return 0; | 165 | return NvResult::Success; |
| 141 | } | 166 | } |
| 142 | 167 | ||
| 143 | u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { | 168 | NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { |
| 144 | IoctlAllocObjCtx params{}; | 169 | IoctlAllocObjCtx params{}; |
| 145 | std::memcpy(¶ms, input.data(), input.size()); | 170 | std::memcpy(¶ms, input.data(), input.size()); |
| 146 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 171 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| @@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 148 | 173 | ||
| 149 | params.obj_id = 0x0; | 174 | params.obj_id = 0x0; |
| 150 | std::memcpy(output.data(), ¶ms, output.size()); | 175 | std::memcpy(output.data(), ¶ms, output.size()); |
| 151 | return 0; | 176 | return NvResult::Success; |
| 152 | } | 177 | } |
| 153 | 178 | ||
| 154 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { | 179 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { |
| @@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence | |||
| 192 | return result; | 217 | return result; |
| 193 | } | 218 | } |
| 194 | 219 | ||
| 195 | u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 220 | NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 196 | Tegra::CommandList&& entries) { | 221 | Tegra::CommandList&& entries) { |
| 197 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | 222 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, |
| 198 | params.num_entries, params.flags.raw); | 223 | params.num_entries, params.flags.raw); |
| 199 | 224 | ||
| @@ -227,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out | |||
| 227 | } | 252 | } |
| 228 | 253 | ||
| 229 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 254 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 230 | return 0; | 255 | return NvResult::Success; |
| 231 | } | 256 | } |
| 232 | 257 | ||
| 233 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 258 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 259 | bool kickoff) { | ||
| 234 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 260 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 235 | UNIMPLEMENTED(); | 261 | UNIMPLEMENTED(); |
| 262 | return NvResult::InvalidSize; | ||
| 236 | } | 263 | } |
| 237 | IoctlSubmitGpfifo params{}; | 264 | IoctlSubmitGpfifo params{}; |
| 238 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 265 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 239 | |||
| 240 | Tegra::CommandList entries(params.num_entries); | 266 | Tegra::CommandList entries(params.num_entries); |
| 241 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | 267 | |
| 242 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 268 | if (kickoff) { |
| 269 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), | ||
| 270 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 271 | } else { | ||
| 272 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 273 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 274 | } | ||
| 243 | 275 | ||
| 244 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | 276 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 245 | } | 277 | } |
| 246 | 278 | ||
| 247 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 279 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, |
| 248 | const std::vector<u8>& input2, IoctlVersion version) { | 280 | const std::vector<u8>& input_inline, |
| 281 | std::vector<u8>& output) { | ||
| 249 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 282 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 250 | UNIMPLEMENTED(); | 283 | UNIMPLEMENTED(); |
| 284 | return NvResult::InvalidSize; | ||
| 251 | } | 285 | } |
| 252 | IoctlSubmitGpfifo params{}; | 286 | IoctlSubmitGpfifo params{}; |
| 253 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 287 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 254 | |||
| 255 | Tegra::CommandList entries(params.num_entries); | 288 | Tegra::CommandList entries(params.num_entries); |
| 256 | if (version == IoctlVersion::Version2) { | 289 | std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); |
| 257 | std::memcpy(entries.command_lists.data(), input2.data(), | ||
| 258 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 259 | } else { | ||
| 260 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), | ||
| 261 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 262 | } | ||
| 263 | |||
| 264 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | 290 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 265 | } | 291 | } |
| 266 | 292 | ||
| 267 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 268 | IoctlGetWaitbase params{}; | 294 | IoctlGetWaitbase params{}; |
| 269 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 295 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 270 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 296 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 271 | 297 | ||
| 272 | params.value = 0; // Seems to be hard coded at 0 | 298 | params.value = 0; // Seems to be hard coded at 0 |
| 273 | std::memcpy(output.data(), ¶ms, output.size()); | 299 | std::memcpy(output.data(), ¶ms, output.size()); |
| 274 | return 0; | 300 | return NvResult::Success; |
| 275 | } | 301 | } |
| 276 | 302 | ||
| 277 | u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 303 | NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { |
| 278 | IoctlChannelSetTimeout params{}; | 304 | IoctlChannelSetTimeout params{}; |
| 279 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 305 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 280 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 306 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 281 | 307 | ||
| 282 | return 0; | 308 | return NvResult::Success; |
| 283 | } | 309 | } |
| 284 | 310 | ||
| 285 | u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { | 311 | NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { |
| 286 | IoctlSetTimeslice params{}; | 312 | IoctlSetTimeslice params{}; |
| 287 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); | 313 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); |
| 288 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); | 314 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); |
| 289 | 315 | ||
| 290 | channel_timeslice = params.timeslice; | 316 | channel_timeslice = params.timeslice; |
| 291 | 317 | ||
| 292 | return 0; | 318 | return NvResult::Success; |
| 293 | } | 319 | } |
| 294 | 320 | ||
| 295 | } // namespace Service::Nvidia::Devices | 321 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index a252fc06d..e0298b4fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -20,43 +20,19 @@ class SyncpointManager; | |||
| 20 | namespace Service::Nvidia::Devices { | 20 | namespace Service::Nvidia::Devices { |
| 21 | 21 | ||
| 22 | class nvmap; | 22 | class nvmap; |
| 23 | constexpr u32 NVGPU_IOCTL_MAGIC('H'); | ||
| 24 | constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); | ||
| 25 | constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | ||
| 26 | |||
| 27 | class nvhost_gpu final : public nvdevice { | 23 | class nvhost_gpu final : public nvdevice { |
| 28 | public: | 24 | public: |
| 29 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | 25 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 30 | SyncpointManager& syncpoint_manager); | 26 | SyncpointManager& syncpoint_manager); |
| 31 | ~nvhost_gpu() override; | 27 | ~nvhost_gpu() override; |
| 32 | 28 | ||
| 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 29 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 34 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 30 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 35 | IoctlVersion version) override; | 31 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 32 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 33 | std::vector<u8>& inline_output) override; | ||
| 36 | 34 | ||
| 37 | private: | 35 | private: |
| 38 | enum class IoctlCommand : u32_le { | ||
| 39 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 40 | IocAllocGPFIFOCommand = 0x40084805, | ||
| 41 | IocSetClientDataCommand = 0x40084714, | ||
| 42 | IocGetClientDataCommand = 0x80084715, | ||
| 43 | IocZCullBind = 0xc010480b, | ||
| 44 | IocSetErrorNotifierCommand = 0xC018480C, | ||
| 45 | IocChannelSetPriorityCommand = 0x4004480D, | ||
| 46 | IocEnableCommand = 0x0000480E, | ||
| 47 | IocDisableCommand = 0x0000480F, | ||
| 48 | IocPreemptCommand = 0x00004810, | ||
| 49 | IocForceResetCommand = 0x00004811, | ||
| 50 | IocEventIdControlCommand = 0x40084812, | ||
| 51 | IocGetErrorNotificationCommand = 0xC0104817, | ||
| 52 | IocAllocGPFIFOExCommand = 0x40204818, | ||
| 53 | IocAllocGPFIFOEx2Command = 0xC020481A, | ||
| 54 | IocAllocObjCtxCommand = 0xC0104809, | ||
| 55 | IocChannelGetWaitbaseCommand = 0xC0080003, | ||
| 56 | IocChannelSetTimeoutCommand = 0x40044803, | ||
| 57 | IocChannelSetTimeslice = 0xC004481D, | ||
| 58 | }; | ||
| 59 | |||
| 60 | enum class CtxObjects : u32_le { | 36 | enum class CtxObjects : u32_le { |
| 61 | Ctx2D = 0x902D, | 37 | Ctx2D = 0x902D, |
| 62 | Ctx3D = 0xB197, | 38 | Ctx3D = 0xB197, |
| @@ -67,63 +43,63 @@ private: | |||
| 67 | }; | 43 | }; |
| 68 | 44 | ||
| 69 | struct IoctlSetNvmapFD { | 45 | struct IoctlSetNvmapFD { |
| 70 | u32_le nvmap_fd; | 46 | s32_le nvmap_fd{}; |
| 71 | }; | 47 | }; |
| 72 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 48 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 73 | 49 | ||
| 74 | struct IoctlChannelSetTimeout { | 50 | struct IoctlChannelSetTimeout { |
| 75 | u32_le timeout; | 51 | u32_le timeout{}; |
| 76 | }; | 52 | }; |
| 77 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); | 53 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); |
| 78 | 54 | ||
| 79 | struct IoctlAllocGPFIFO { | 55 | struct IoctlAllocGPFIFO { |
| 80 | u32_le num_entries; | 56 | u32_le num_entries{}; |
| 81 | u32_le flags; | 57 | u32_le flags{}; |
| 82 | }; | 58 | }; |
| 83 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); | 59 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); |
| 84 | 60 | ||
| 85 | struct IoctlClientData { | 61 | struct IoctlClientData { |
| 86 | u64_le data; | 62 | u64_le data{}; |
| 87 | }; | 63 | }; |
| 88 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); | 64 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); |
| 89 | 65 | ||
| 90 | struct IoctlZCullBind { | 66 | struct IoctlZCullBind { |
| 91 | u64_le gpu_va; | 67 | u64_le gpu_va{}; |
| 92 | u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf | 68 | u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf |
| 93 | INSERT_PADDING_WORDS(1); | 69 | INSERT_PADDING_WORDS(1); |
| 94 | }; | 70 | }; |
| 95 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); | 71 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); |
| 96 | 72 | ||
| 97 | struct IoctlSetErrorNotifier { | 73 | struct IoctlSetErrorNotifier { |
| 98 | u64_le offset; | 74 | u64_le offset{}; |
| 99 | u64_le size; | 75 | u64_le size{}; |
| 100 | u32_le mem; // nvmap object handle | 76 | u32_le mem{}; // nvmap object handle |
| 101 | INSERT_PADDING_WORDS(1); | 77 | INSERT_PADDING_WORDS(1); |
| 102 | }; | 78 | }; |
| 103 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); | 79 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); |
| 104 | 80 | ||
| 105 | struct IoctlChannelSetPriority { | 81 | struct IoctlChannelSetPriority { |
| 106 | u32_le priority; | 82 | u32_le priority{}; |
| 107 | }; | 83 | }; |
| 108 | static_assert(sizeof(IoctlChannelSetPriority) == 4, | 84 | static_assert(sizeof(IoctlChannelSetPriority) == 4, |
| 109 | "IoctlChannelSetPriority is incorrect size"); | 85 | "IoctlChannelSetPriority is incorrect size"); |
| 110 | 86 | ||
| 111 | struct IoctlSetTimeslice { | 87 | struct IoctlSetTimeslice { |
| 112 | u32_le timeslice; | 88 | u32_le timeslice{}; |
| 113 | }; | 89 | }; |
| 114 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); | 90 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); |
| 115 | 91 | ||
| 116 | struct IoctlEventIdControl { | 92 | struct IoctlEventIdControl { |
| 117 | u32_le cmd; // 0=disable, 1=enable, 2=clear | 93 | u32_le cmd{}; // 0=disable, 1=enable, 2=clear |
| 118 | u32_le id; | 94 | u32_le id{}; |
| 119 | }; | 95 | }; |
| 120 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); | 96 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); |
| 121 | 97 | ||
| 122 | struct IoctlGetErrorNotification { | 98 | struct IoctlGetErrorNotification { |
| 123 | u64_le timestamp; | 99 | u64_le timestamp{}; |
| 124 | u32_le info32; | 100 | u32_le info32{}; |
| 125 | u16_le info16; | 101 | u16_le info16{}; |
| 126 | u16_le status; // always 0xFFFF | 102 | u16_le status{}; // always 0xFFFF |
| 127 | }; | 103 | }; |
| 128 | static_assert(sizeof(IoctlGetErrorNotification) == 16, | 104 | static_assert(sizeof(IoctlGetErrorNotification) == 16, |
| 129 | "IoctlGetErrorNotification is incorrect size"); | 105 | "IoctlGetErrorNotification is incorrect size"); |
| @@ -131,39 +107,39 @@ private: | |||
| 131 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); | 107 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); |
| 132 | 108 | ||
| 133 | struct IoctlAllocGpfifoEx { | 109 | struct IoctlAllocGpfifoEx { |
| 134 | u32_le num_entries; | 110 | u32_le num_entries{}; |
| 135 | u32_le flags; | 111 | u32_le flags{}; |
| 136 | u32_le unk0; | 112 | u32_le unk0{}; |
| 137 | u32_le unk1; | 113 | u32_le unk1{}; |
| 138 | u32_le unk2; | 114 | u32_le unk2{}; |
| 139 | u32_le unk3; | 115 | u32_le unk3{}; |
| 140 | u32_le unk4; | 116 | u32_le unk4{}; |
| 141 | u32_le unk5; | 117 | u32_le unk5{}; |
| 142 | }; | 118 | }; |
| 143 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); | 119 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); |
| 144 | 120 | ||
| 145 | struct IoctlAllocGpfifoEx2 { | 121 | struct IoctlAllocGpfifoEx2 { |
| 146 | u32_le num_entries; // in | 122 | u32_le num_entries{}; // in |
| 147 | u32_le flags; // in | 123 | u32_le flags{}; // in |
| 148 | u32_le unk0; // in (1 works) | 124 | u32_le unk0{}; // in (1 works) |
| 149 | Fence fence_out; // out | 125 | Fence fence_out{}; // out |
| 150 | u32_le unk1; // in | 126 | u32_le unk1{}; // in |
| 151 | u32_le unk2; // in | 127 | u32_le unk2{}; // in |
| 152 | u32_le unk3; // in | 128 | u32_le unk3{}; // in |
| 153 | }; | 129 | }; |
| 154 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); | 130 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); |
| 155 | 131 | ||
| 156 | struct IoctlAllocObjCtx { | 132 | struct IoctlAllocObjCtx { |
| 157 | u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, | 133 | u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, |
| 158 | // 0xB06F=channel_gpfifo | 134 | // 0xB06F=channel_gpfifo |
| 159 | u32_le flags; | 135 | u32_le flags{}; |
| 160 | u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported | 136 | u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported |
| 161 | }; | 137 | }; |
| 162 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); | 138 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); |
| 163 | 139 | ||
| 164 | struct IoctlSubmitGpfifo { | 140 | struct IoctlSubmitGpfifo { |
| 165 | u64_le address; // pointer to gpfifo entry structs | 141 | u64_le address{}; // pointer to gpfifo entry structs |
| 166 | u32_le num_entries; // number of fence objects being submitted | 142 | u32_le num_entries{}; // number of fence objects being submitted |
| 167 | union { | 143 | union { |
| 168 | u32_le raw; | 144 | u32_le raw; |
| 169 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list | 145 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| @@ -172,7 +148,7 @@ private: | |||
| 172 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt | 148 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt |
| 173 | BitField<8, 1, u32_le> increment; // increment the returned fence | 149 | BitField<8, 1, u32_le> increment; // increment the returned fence |
| 174 | } flags; | 150 | } flags; |
| 175 | Fence fence_out; // returned new fence object for others to wait on | 151 | Fence fence_out{}; // returned new fence object for others to wait on |
| 176 | 152 | ||
| 177 | u32 AddIncrementValue() const { | 153 | u32 AddIncrementValue() const { |
| 178 | return flags.add_increment.Value() << 1; | 154 | return flags.add_increment.Value() << 1; |
| @@ -182,33 +158,34 @@ private: | |||
| 182 | "IoctlSubmitGpfifo is incorrect size"); | 158 | "IoctlSubmitGpfifo is incorrect size"); |
| 183 | 159 | ||
| 184 | struct IoctlGetWaitbase { | 160 | struct IoctlGetWaitbase { |
| 185 | u32 unknown; // seems to be ignored? Nintendo added this | 161 | u32 unknown{}; // seems to be ignored? Nintendo added this |
| 186 | u32 value; | 162 | u32 value{}; |
| 187 | }; | 163 | }; |
| 188 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); | 164 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); |
| 189 | 165 | ||
| 190 | u32_le nvmap_fd{}; | 166 | s32_le nvmap_fd{}; |
| 191 | u64_le user_data{}; | 167 | u64_le user_data{}; |
| 192 | IoctlZCullBind zcull_params{}; | 168 | IoctlZCullBind zcull_params{}; |
| 193 | u32_le channel_priority{}; | 169 | u32_le channel_priority{}; |
| 194 | u32_le channel_timeslice{}; | 170 | u32_le channel_timeslice{}; |
| 195 | 171 | ||
| 196 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 172 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 197 | u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 173 | NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 198 | u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 174 | NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 199 | u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); | 175 | NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); |
| 200 | u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); | 176 | NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); |
| 201 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); | 177 | NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); |
| 202 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 178 | NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 203 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 179 | NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 204 | u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 180 | NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 205 | Tegra::CommandList&& entries); | 181 | Tegra::CommandList&& entries); |
| 206 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 182 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 207 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 183 | bool kickoff = false); |
| 208 | const std::vector<u8>& input2, IoctlVersion version); | 184 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, |
| 209 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 185 | std::vector<u8>& output); |
| 210 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 186 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 211 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | 187 | NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 188 | NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 212 | 189 | ||
| 213 | std::shared_ptr<nvmap> nvmap_dev; | 190 | std::shared_ptr<nvmap> nvmap_dev; |
| 214 | SyncpointManager& syncpoint_manager; | 191 | SyncpointManager& syncpoint_manager; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index b6df48360..d8735491c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} | 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} |
| 16 | nvhost_nvdec::~nvhost_nvdec() = default; | 16 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 19 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 19 | std::vector<u8>& output) { |
| 20 | IoctlVersion version) { | 20 | switch (command.group) { |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | case 0x0: |
| 22 | command.raw, input.size(), output.size()); | 22 | switch (command.cmd) { |
| 23 | 23 | case 0x1: | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | return Submit(input, output); |
| 25 | case IoctlCommand::IocSetNVMAPfdCommand: | 25 | case 0x2: |
| 26 | return SetNVMAPfd(input); | 26 | return GetSyncpoint(input, output); |
| 27 | case IoctlCommand::IocSubmit: | 27 | case 0x3: |
| 28 | return Submit(input, output); | 28 | return GetWaitbase(input, output); |
| 29 | case IoctlCommand::IocGetSyncpoint: | 29 | case 0x7: |
| 30 | return GetSyncpoint(input, output); | 30 | return SetSubmitTimeout(input, output); |
| 31 | case IoctlCommand::IocGetWaitbase: | 31 | case 0x9: |
| 32 | return GetWaitbase(input, output); | 32 | return MapBuffer(input, output); |
| 33 | case IoctlCommand::IocMapBuffer: | 33 | case 0xa: { |
| 34 | case IoctlCommand::IocMapBuffer2: | 34 | if (command.length == 0x1c) { |
| 35 | case IoctlCommand::IocMapBuffer3: | 35 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); |
| 36 | case IoctlCommand::IocMapBufferEx: | 36 | Tegra::ChCommandHeaderList cmdlist(1); |
| 37 | return MapBuffer(input, output); | 37 | cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; |
| 38 | case IoctlCommand::IocUnmapBufferEx: { | 38 | system.GPU().PushCommandBuffer(cmdlist); |
| 39 | // This command is sent when the video stream has ended, flush all video contexts | 39 | } |
| 40 | // This is usually sent in the folowing order: vic, nvdec, vic. | 40 | return UnmapBuffer(input, output); |
| 41 | // Inform the GPU to clear any remaining nvdec buffers when this is detected. | 41 | } |
| 42 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | 42 | default: |
| 43 | Tegra::ChCommandHeaderList cmdlist(1); | 43 | break; |
| 44 | cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; | 44 | } |
| 45 | system.GPU().PushCommandBuffer(cmdlist); | 45 | break; |
| 46 | [[fallthrough]]; // fallthrough to unmap buffers | 46 | case 'H': |
| 47 | }; | 47 | switch (command.cmd) { |
| 48 | case IoctlCommand::IocUnmapBuffer: | 48 | case 0x1: |
| 49 | case IoctlCommand::IocUnmapBuffer2: | 49 | return SetNVMAPfd(input); |
| 50 | case IoctlCommand::IocUnmapBuffer3: | 50 | default: |
| 51 | return UnmapBuffer(input, output); | 51 | break; |
| 52 | case IoctlCommand::IocSetSubmitTimeout: | 52 | } |
| 53 | return SetSubmitTimeout(input, output); | 53 | break; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); | 56 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 57 | return 0; | 57 | return NvResult::NotImplemented; |
| 58 | } | ||
| 59 | |||
| 60 | NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 61 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 62 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 63 | return NvResult::NotImplemented; | ||
| 64 | } | ||
| 65 | |||
| 66 | NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 67 | std::vector<u8>& inline_output) { | ||
| 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 69 | return NvResult::NotImplemented; | ||
| 58 | } | 70 | } |
| 59 | 71 | ||
| 60 | } // namespace Service::Nvidia::Devices | 72 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 102777ddd..79b8b6de1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -14,26 +14,11 @@ public: | |||
| 14 | explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 14 | explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 15 | ~nvhost_nvdec() override; | 15 | ~nvhost_nvdec() override; |
| 16 | 16 | ||
| 17 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 17 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 18 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 18 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 19 | IoctlVersion version) override; | 19 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 20 | 20 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | |
| 21 | private: | 21 | std::vector<u8>& inline_output) override; |
| 22 | enum class IoctlCommand : u32_le { | ||
| 23 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 24 | IocSubmit = 0xC0400001, | ||
| 25 | IocGetSyncpoint = 0xC0080002, | ||
| 26 | IocGetWaitbase = 0xC0080003, | ||
| 27 | IocMapBuffer = 0xC01C0009, | ||
| 28 | IocMapBuffer2 = 0xC16C0009, | ||
| 29 | IocMapBuffer3 = 0xC15C0009, | ||
| 30 | IocMapBufferEx = 0xC0A40009, | ||
| 31 | IocUnmapBuffer = 0xC0A4000A, | ||
| 32 | IocUnmapBuffer2 = 0xC16C000A, | ||
| 33 | IocUnmapBufferEx = 0xC01C000A, | ||
| 34 | IocUnmapBuffer3 = 0xC15C000A, | ||
| 35 | IocSetSubmitTimeout = 0x40040007, | ||
| 36 | }; | ||
| 37 | }; | 22 | }; |
| 38 | 23 | ||
| 39 | } // namespace Service::Nvidia::Devices | 24 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 30f03f845..b49cecb42 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s | |||
| 36 | } | 36 | } |
| 37 | } // Anonymous namespace | 37 | } // Anonymous namespace |
| 38 | 38 | ||
| 39 | namespace NvErrCodes { | ||
| 40 | constexpr u32 Success{}; | ||
| 41 | [[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 42 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 43 | } // namespace NvErrCodes | ||
| 44 | |||
| 45 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 39 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 46 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 40 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 47 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; | 41 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; |
| 48 | 42 | ||
| 49 | u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { | 43 | NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { |
| 50 | IoctlSetNvmapFD params{}; | 44 | IoctlSetNvmapFD params{}; |
| 51 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); | 45 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); |
| 52 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 46 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 53 | 47 | ||
| 54 | nvmap_fd = params.nvmap_fd; | 48 | nvmap_fd = params.nvmap_fd; |
| 55 | return 0; | 49 | return NvResult::Success; |
| 56 | } | 50 | } |
| 57 | 51 | ||
| 58 | u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | 52 | NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { |
| 59 | IoctlSubmit params{}; | 53 | IoctlSubmit params{}; |
| 60 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | 54 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); |
| 61 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); | 55 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); |
| @@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o | |||
| 83 | 77 | ||
| 84 | for (const auto& cmd_buffer : command_buffers) { | 78 | for (const auto& cmd_buffer : command_buffers) { |
| 85 | auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); | 79 | auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); |
| 86 | ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;); | 80 | ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); |
| 87 | const auto map = FindBufferMap(object->dma_map_addr); | 81 | const auto map = FindBufferMap(object->dma_map_addr); |
| 88 | if (!map) { | 82 | if (!map) { |
| 89 | LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", | 83 | LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", |
| 90 | object->addr, object->dma_map_addr); | 84 | object->addr, object->dma_map_addr); |
| 91 | return 0; | 85 | return NvResult::Success; |
| 92 | } | 86 | } |
| 93 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); | 87 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); |
| 94 | gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), | 88 | gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), |
| @@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o | |||
| 105 | offset = WriteVectors(output, syncpt_increments, offset); | 99 | offset = WriteVectors(output, syncpt_increments, offset); |
| 106 | offset = WriteVectors(output, wait_checks, offset); | 100 | offset = WriteVectors(output, wait_checks, offset); |
| 107 | 101 | ||
| 108 | return NvErrCodes::Success; | 102 | return NvResult::Success; |
| 109 | } | 103 | } |
| 110 | 104 | ||
| 111 | u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | 105 | NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { |
| 112 | IoctlGetSyncpoint params{}; | 106 | IoctlGetSyncpoint params{}; |
| 113 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); | 107 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); |
| 114 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); | 108 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); |
| @@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector< | |||
| 118 | params.value = 0; | 112 | params.value = 0; |
| 119 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); | 113 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); |
| 120 | 114 | ||
| 121 | return NvErrCodes::Success; | 115 | return NvResult::Success; |
| 122 | } | 116 | } |
| 123 | 117 | ||
| 124 | u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 118 | NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 125 | IoctlGetWaitbase params{}; | 119 | IoctlGetWaitbase params{}; |
| 126 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 120 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 127 | params.value = 0; // Seems to be hard coded at 0 | 121 | params.value = 0; // Seems to be hard coded at 0 |
| 128 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); | 122 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); |
| 129 | return 0; | 123 | return NvResult::Success; |
| 130 | } | 124 | } |
| 131 | 125 | ||
| 132 | u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 126 | NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 133 | IoctlMapBuffer params{}; | 127 | IoctlMapBuffer params{}; |
| 134 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 128 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 135 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 129 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8> | |||
| 143 | if (!object) { | 137 | if (!object) { |
| 144 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | 138 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); |
| 145 | std::memcpy(output.data(), ¶ms, output.size()); | 139 | std::memcpy(output.data(), ¶ms, output.size()); |
| 146 | return NvErrCodes::InvalidInput; | 140 | return NvResult::InvalidState; |
| 147 | } | 141 | } |
| 148 | if (object->dma_map_addr == 0) { | 142 | if (object->dma_map_addr == 0) { |
| 149 | // NVDEC and VIC memory is in the 32-bit address space | 143 | // NVDEC and VIC memory is in the 32-bit address space |
| @@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8> | |||
| 165 | std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), | 159 | std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), |
| 166 | cmd_buffer_handles.size() * sizeof(MapBufferEntry)); | 160 | cmd_buffer_handles.size() * sizeof(MapBufferEntry)); |
| 167 | 161 | ||
| 168 | return NvErrCodes::Success; | 162 | return NvResult::Success; |
| 169 | } | 163 | } |
| 170 | 164 | ||
| 171 | u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 165 | NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 172 | IoctlMapBuffer params{}; | 166 | IoctlMapBuffer params{}; |
| 173 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 167 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 174 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 168 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u | |||
| 181 | if (!object) { | 175 | if (!object) { |
| 182 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | 176 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); |
| 183 | std::memcpy(output.data(), ¶ms, output.size()); | 177 | std::memcpy(output.data(), ¶ms, output.size()); |
| 184 | return NvErrCodes::InvalidInput; | 178 | return NvResult::InvalidState; |
| 185 | } | 179 | } |
| 186 | if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { | 180 | if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { |
| 187 | gpu.MemoryManager().Unmap(object->dma_map_addr, *size); | 181 | gpu.MemoryManager().Unmap(object->dma_map_addr, *size); |
| @@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u | |||
| 193 | object->dma_map_addr = 0; | 187 | object->dma_map_addr = 0; |
| 194 | } | 188 | } |
| 195 | std::memset(output.data(), 0, output.size()); | 189 | std::memset(output.data(), 0, output.size()); |
| 196 | return NvErrCodes::Success; | 190 | return NvResult::Success; |
| 197 | } | 191 | } |
| 198 | 192 | ||
| 199 | u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 193 | NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, |
| 194 | std::vector<u8>& output) { | ||
| 200 | std::memcpy(&submit_timeout, input.data(), input.size()); | 195 | std::memcpy(&submit_timeout, input.data(), input.size()); |
| 201 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 196 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 202 | return NvErrCodes::Success; | 197 | return NvResult::Success; |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( | 200 | std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( |
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 c249c5349..86ba3a4d1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -18,9 +18,37 @@ public: | |||
| 18 | explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 18 | explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 19 | ~nvhost_nvdec_common() override; | 19 | ~nvhost_nvdec_common() override; |
| 20 | 20 | ||
| 21 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | /** |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | * Handles an ioctl1 request. |
| 23 | IoctlVersion version) = 0; | 23 | * @param command The ioctl command id. |
| 24 | * @param input A buffer containing the input data for the ioctl. | ||
| 25 | * @param output A buffer where the output data will be written to. | ||
| 26 | * @returns The result code of the ioctl. | ||
| 27 | */ | ||
| 28 | virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, | ||
| 29 | std::vector<u8>& output) = 0; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Handles an ioctl2 request. | ||
| 33 | * @param command The ioctl command id. | ||
| 34 | * @param input A buffer containing the input data for the ioctl. | ||
| 35 | * @param inline_input A buffer containing the input data for the ioctl which has been inlined. | ||
| 36 | * @param output A buffer where the output data will be written to. | ||
| 37 | * @returns The result code of the ioctl. | ||
| 38 | */ | ||
| 39 | virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 40 | const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Handles an ioctl3 request. | ||
| 44 | * @param command The ioctl command id. | ||
| 45 | * @param input A buffer containing the input data for the ioctl. | ||
| 46 | * @param output A buffer where the output data will be written to. | ||
| 47 | * @param inline_output A buffer where the inlined output data will be written to. | ||
| 48 | * @returns The result code of the ioctl. | ||
| 49 | */ | ||
| 50 | virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 51 | std::vector<u8>& inline_output) = 0; | ||
| 24 | 52 | ||
| 25 | protected: | 53 | protected: |
| 26 | class BufferMap final { | 54 | class BufferMap final { |
| @@ -63,102 +91,102 @@ protected: | |||
| 63 | }; | 91 | }; |
| 64 | 92 | ||
| 65 | struct IoctlSetNvmapFD { | 93 | struct IoctlSetNvmapFD { |
| 66 | u32_le nvmap_fd; | 94 | s32_le nvmap_fd{}; |
| 67 | }; | 95 | }; |
| 68 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 96 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 69 | 97 | ||
| 70 | struct IoctlSubmitCommandBuffer { | 98 | struct IoctlSubmitCommandBuffer { |
| 71 | u32_le id; | 99 | u32_le id{}; |
| 72 | u32_le offset; | 100 | u32_le offset{}; |
| 73 | u32_le count; | 101 | u32_le count{}; |
| 74 | }; | 102 | }; |
| 75 | static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, | 103 | static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, |
| 76 | "IoctlSubmitCommandBuffer is incorrect size"); | 104 | "IoctlSubmitCommandBuffer is incorrect size"); |
| 77 | struct IoctlSubmit { | 105 | struct IoctlSubmit { |
| 78 | u32_le cmd_buffer_count; | 106 | u32_le cmd_buffer_count{}; |
| 79 | u32_le relocation_count; | 107 | u32_le relocation_count{}; |
| 80 | u32_le syncpoint_count; | 108 | u32_le syncpoint_count{}; |
| 81 | u32_le fence_count; | 109 | u32_le fence_count{}; |
| 82 | }; | 110 | }; |
| 83 | static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); | 111 | static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); |
| 84 | 112 | ||
| 85 | struct CommandBuffer { | 113 | struct CommandBuffer { |
| 86 | s32 memory_id; | 114 | s32 memory_id{}; |
| 87 | u32 offset; | 115 | u32 offset{}; |
| 88 | s32 word_count; | 116 | s32 word_count{}; |
| 89 | }; | 117 | }; |
| 90 | static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); | 118 | static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); |
| 91 | 119 | ||
| 92 | struct Reloc { | 120 | struct Reloc { |
| 93 | s32 cmdbuffer_memory; | 121 | s32 cmdbuffer_memory{}; |
| 94 | s32 cmdbuffer_offset; | 122 | s32 cmdbuffer_offset{}; |
| 95 | s32 target; | 123 | s32 target{}; |
| 96 | s32 target_offset; | 124 | s32 target_offset{}; |
| 97 | }; | 125 | }; |
| 98 | static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); | 126 | static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); |
| 99 | 127 | ||
| 100 | struct SyncptIncr { | 128 | struct SyncptIncr { |
| 101 | u32 id; | 129 | u32 id{}; |
| 102 | u32 increments; | 130 | u32 increments{}; |
| 103 | }; | 131 | }; |
| 104 | static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); | 132 | static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); |
| 105 | 133 | ||
| 106 | struct Fence { | 134 | struct Fence { |
| 107 | u32 id; | 135 | u32 id{}; |
| 108 | u32 value; | 136 | u32 value{}; |
| 109 | }; | 137 | }; |
| 110 | static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); | 138 | static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); |
| 111 | 139 | ||
| 112 | struct IoctlGetSyncpoint { | 140 | struct IoctlGetSyncpoint { |
| 113 | // Input | 141 | // Input |
| 114 | u32_le param; | 142 | u32_le param{}; |
| 115 | // Output | 143 | // Output |
| 116 | u32_le value; | 144 | u32_le value{}; |
| 117 | }; | 145 | }; |
| 118 | static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); | 146 | static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); |
| 119 | 147 | ||
| 120 | struct IoctlGetWaitbase { | 148 | struct IoctlGetWaitbase { |
| 121 | u32_le unknown; // seems to be ignored? Nintendo added this | 149 | u32_le unknown{}; // seems to be ignored? Nintendo added this |
| 122 | u32_le value; | 150 | u32_le value{}; |
| 123 | }; | 151 | }; |
| 124 | static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); | 152 | static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); |
| 125 | 153 | ||
| 126 | struct IoctlMapBuffer { | 154 | struct IoctlMapBuffer { |
| 127 | u32_le num_entries; | 155 | u32_le num_entries{}; |
| 128 | u32_le data_address; // Ignored by the driver. | 156 | u32_le data_address{}; // Ignored by the driver. |
| 129 | u32_le attach_host_ch_das; | 157 | u32_le attach_host_ch_das{}; |
| 130 | }; | 158 | }; |
| 131 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | 159 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); |
| 132 | 160 | ||
| 133 | struct IocGetIdParams { | 161 | struct IocGetIdParams { |
| 134 | // Input | 162 | // Input |
| 135 | u32_le param; | 163 | u32_le param{}; |
| 136 | // Output | 164 | // Output |
| 137 | u32_le value; | 165 | u32_le value{}; |
| 138 | }; | 166 | }; |
| 139 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 167 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 140 | 168 | ||
| 141 | // Used for mapping and unmapping command buffers | 169 | // Used for mapping and unmapping command buffers |
| 142 | struct MapBufferEntry { | 170 | struct MapBufferEntry { |
| 143 | u32_le map_handle; | 171 | u32_le map_handle{}; |
| 144 | u32_le map_address; | 172 | u32_le map_address{}; |
| 145 | }; | 173 | }; |
| 146 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | 174 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); |
| 147 | 175 | ||
| 148 | /// Ioctl command implementations | 176 | /// Ioctl command implementations |
| 149 | u32 SetNVMAPfd(const std::vector<u8>& input); | 177 | NvResult SetNVMAPfd(const std::vector<u8>& input); |
| 150 | u32 Submit(const std::vector<u8>& input, std::vector<u8>& output); | 178 | NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); |
| 151 | u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); | 179 | NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); |
| 152 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 180 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 153 | u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 181 | NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 154 | u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 182 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 155 | u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 183 | NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 156 | 184 | ||
| 157 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | 185 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; |
| 158 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | 186 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); |
| 159 | std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); | 187 | std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); |
| 160 | 188 | ||
| 161 | u32_le nvmap_fd{}; | 189 | s32_le nvmap_fd{}; |
| 162 | u32_le submit_timeout{}; | 190 | u32_le submit_timeout{}; |
| 163 | std::shared_ptr<nvmap> nvmap_dev; | 191 | std::shared_ptr<nvmap> nvmap_dev; |
| 164 | 192 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 96e7b7dab..2d06955c0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} | 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 16 | NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 17 | std::vector<u8>& output) { |
| 18 | IoctlVersion version) { | 18 | switch (command.group) { |
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | case 'H': |
| 20 | command.raw, input.size(), output.size()); | 20 | switch (command.cmd) { |
| 21 | 21 | case 0x1: | |
| 22 | switch (static_cast<IoctlCommand>(command.raw)) { | 22 | return SetNVMAPfd(input, output); |
| 23 | case IoctlCommand::IocSetNVMAPfdCommand: | 23 | default: |
| 24 | return SetNVMAPfd(input, output); | 24 | break; |
| 25 | } | ||
| 26 | break; | ||
| 27 | default: | ||
| 28 | break; | ||
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 31 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 28 | return 0; | 32 | return NvResult::NotImplemented; |
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 35 | NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 36 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 37 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 38 | return NvResult::NotImplemented; | ||
| 39 | } | ||
| 40 | |||
| 41 | NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 42 | std::vector<u8>& inline_output) { | ||
| 43 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 44 | return NvResult::NotImplemented; | ||
| 45 | } | ||
| 46 | |||
| 47 | NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 32 | IoctlSetNvmapFD params{}; | 48 | IoctlSetNvmapFD params{}; |
| 33 | std::memcpy(¶ms, input.data(), input.size()); | 49 | std::memcpy(¶ms, input.data(), input.size()); |
| 34 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 50 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 35 | 51 | ||
| 36 | nvmap_fd = params.nvmap_fd; | 52 | nvmap_fd = params.nvmap_fd; |
| 37 | return 0; | 53 | return NvResult::Success; |
| 38 | } | 54 | } |
| 39 | 55 | ||
| 40 | } // namespace Service::Nvidia::Devices | 56 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 98dcac52f..43948d18d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -16,23 +16,21 @@ public: | |||
| 16 | explicit nvhost_nvjpg(Core::System& system); | 16 | explicit nvhost_nvjpg(Core::System& system); |
| 17 | ~nvhost_nvjpg() override; | 17 | ~nvhost_nvjpg() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct IoctlSetNvmapFD { | 26 | struct IoctlSetNvmapFD { |
| 29 | u32_le nvmap_fd; | 27 | s32_le nvmap_fd{}; |
| 30 | }; | 28 | }; |
| 31 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 29 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 32 | 30 | ||
| 33 | u32_le nvmap_fd{}; | 31 | s32_le nvmap_fd{}; |
| 34 | 32 | ||
| 35 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 33 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | } // namespace Service::Nvidia::Devices | 36 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 60db54d00..805fe86ae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -15,36 +15,50 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | |||
| 15 | 15 | ||
| 16 | nvhost_vic::~nvhost_vic() = default; | 16 | nvhost_vic::~nvhost_vic() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 19 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 19 | switch (command.group) { |
| 20 | IoctlVersion version) { | 20 | case 0x0: |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | switch (command.cmd) { |
| 22 | command.raw, input.size(), output.size()); | 22 | case 0x1: |
| 23 | 23 | return Submit(input, output); | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | case 0x2: |
| 25 | case IoctlCommand::IocSetNVMAPfdCommand: | 25 | return GetSyncpoint(input, output); |
| 26 | return SetNVMAPfd(input); | 26 | case 0x3: |
| 27 | case IoctlCommand::IocSubmit: | 27 | return GetWaitbase(input, output); |
| 28 | return Submit(input, output); | 28 | case 0x9: |
| 29 | case IoctlCommand::IocGetSyncpoint: | 29 | return MapBuffer(input, output); |
| 30 | return GetSyncpoint(input, output); | 30 | case 0xa: |
| 31 | case IoctlCommand::IocGetWaitbase: | 31 | return UnmapBuffer(input, output); |
| 32 | return GetWaitbase(input, output); | 32 | default: |
| 33 | case IoctlCommand::IocMapBuffer: | 33 | break; |
| 34 | case IoctlCommand::IocMapBuffer2: | 34 | } |
| 35 | case IoctlCommand::IocMapBuffer3: | 35 | break; |
| 36 | case IoctlCommand::IocMapBuffer4: | 36 | case 'H': |
| 37 | case IoctlCommand::IocMapBufferEx: | 37 | switch (command.cmd) { |
| 38 | return MapBuffer(input, output); | 38 | case 0x1: |
| 39 | case IoctlCommand::IocUnmapBuffer: | 39 | return SetNVMAPfd(input); |
| 40 | case IoctlCommand::IocUnmapBuffer2: | 40 | default: |
| 41 | case IoctlCommand::IocUnmapBuffer3: | 41 | break; |
| 42 | case IoctlCommand::IocUnmapBufferEx: | 42 | } |
| 43 | return UnmapBuffer(input, output); | 43 | break; |
| 44 | default: | ||
| 45 | break; | ||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); | 48 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 47 | return 0; | 49 | return NvResult::NotImplemented; |
| 50 | } | ||
| 51 | |||
| 52 | NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 53 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 54 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 55 | return NvResult::NotImplemented; | ||
| 56 | } | ||
| 57 | |||
| 58 | NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 59 | std::vector<u8>& inline_output) { | ||
| 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 61 | return NvResult::NotImplemented; | ||
| 48 | } | 62 | } |
| 49 | 63 | ||
| 50 | } // namespace Service::Nvidia::Devices | 64 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index f975b190c..b2e11f4d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common { | |||
| 13 | public: | 13 | public: |
| 14 | explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 14 | explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 15 | ~nvhost_vic(); | 15 | ~nvhost_vic(); |
| 16 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 18 | IoctlVersion version) override; | ||
| 19 | 16 | ||
| 20 | private: | 17 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 21 | enum class IoctlCommand : u32_le { | 18 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 22 | IocSetNVMAPfdCommand = 0x40044801, | 19 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 23 | IocSubmit = 0xC0400001, | 20 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 24 | IocGetSyncpoint = 0xC0080002, | 21 | std::vector<u8>& inline_output) override; |
| 25 | IocGetWaitbase = 0xC0080003, | ||
| 26 | IocMapBuffer = 0xC01C0009, | ||
| 27 | IocMapBuffer2 = 0xC0340009, | ||
| 28 | IocMapBuffer3 = 0xC0140009, | ||
| 29 | IocMapBuffer4 = 0xC00C0009, | ||
| 30 | IocMapBufferEx = 0xC03C0009, | ||
| 31 | IocUnmapBuffer = 0xC03C000A, | ||
| 32 | IocUnmapBuffer2 = 0xC034000A, | ||
| 33 | IocUnmapBuffer3 = 0xC00C000A, | ||
| 34 | IocUnmapBufferEx = 0xC01C000A, | ||
| 35 | }; | ||
| 36 | }; | 22 | }; |
| 37 | } // namespace Service::Nvidia::Devices | 23 | } // 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 9436e16ad..4015a2740 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -11,13 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | 13 | ||
| 14 | namespace NvErrCodes { | ||
| 15 | enum { | ||
| 16 | OperationNotPermitted = -1, | ||
| 17 | InvalidValue = -22, | ||
| 18 | }; | ||
| 19 | } | ||
| 20 | |||
| 21 | nvmap::nvmap(Core::System& system) : nvdevice(system) { | 14 | nvmap::nvmap(Core::System& system) : nvdevice(system) { |
| 22 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to | 15 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to |
| 23 | // represent this. | 16 | // represent this. |
| @@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) { | |||
| 26 | 19 | ||
| 27 | nvmap::~nvmap() = default; | 20 | nvmap::~nvmap() = default; |
| 28 | 21 | ||
| 22 | NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 23 | switch (command.group) { | ||
| 24 | case 0x1: | ||
| 25 | switch (command.cmd) { | ||
| 26 | case 0x1: | ||
| 27 | return IocCreate(input, output); | ||
| 28 | case 0x3: | ||
| 29 | return IocFromId(input, output); | ||
| 30 | case 0x4: | ||
| 31 | return IocAlloc(input, output); | ||
| 32 | case 0x5: | ||
| 33 | return IocFree(input, output); | ||
| 34 | case 0x9: | ||
| 35 | return IocParam(input, output); | ||
| 36 | case 0xe: | ||
| 37 | return IocGetId(input, output); | ||
| 38 | default: | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | break; | ||
| 42 | default: | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | |||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 57 | std::vector<u8>& inline_output) { | ||
| 58 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 59 | return NvResult::NotImplemented; | ||
| 60 | } | ||
| 61 | |||
| 29 | VAddr nvmap::GetObjectAddress(u32 handle) const { | 62 | VAddr nvmap::GetObjectAddress(u32 handle) const { |
| 30 | auto object = GetObject(handle); | 63 | auto object = GetObject(handle); |
| 31 | ASSERT(object); | 64 | ASSERT(object); |
| @@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { | |||
| 33 | return object->addr; | 66 | return object->addr; |
| 34 | } | 67 | } |
| 35 | 68 | ||
| 36 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 37 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 38 | IoctlVersion version) { | ||
| 39 | switch (static_cast<IoctlCommand>(command.raw)) { | ||
| 40 | case IoctlCommand::Create: | ||
| 41 | return IocCreate(input, output); | ||
| 42 | case IoctlCommand::Alloc: | ||
| 43 | return IocAlloc(input, output); | ||
| 44 | case IoctlCommand::GetId: | ||
| 45 | return IocGetId(input, output); | ||
| 46 | case IoctlCommand::FromId: | ||
| 47 | return IocFromId(input, output); | ||
| 48 | case IoctlCommand::Param: | ||
| 49 | return IocParam(input, output); | ||
| 50 | case IoctlCommand::Free: | ||
| 51 | return IocFree(input, output); | ||
| 52 | } | ||
| 53 | |||
| 54 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | u32 nvmap::CreateObject(u32 size) { | 69 | u32 nvmap::CreateObject(u32 size) { |
| 59 | // Create a new nvmap object and obtain a handle to it. | 70 | // Create a new nvmap object and obtain a handle to it. |
| 60 | auto object = std::make_shared<Object>(); | 71 | auto object = std::make_shared<Object>(); |
| @@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) { | |||
| 70 | return handle; | 81 | return handle; |
| 71 | } | 82 | } |
| 72 | 83 | ||
| 73 | u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | 84 | NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { |
| 74 | IocCreateParams params; | 85 | IocCreateParams params; |
| 75 | std::memcpy(¶ms, input.data(), sizeof(params)); | 86 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 76 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 87 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 77 | 88 | ||
| 78 | if (!params.size) { | 89 | if (!params.size) { |
| 79 | LOG_ERROR(Service_NVDRV, "Size is 0"); | 90 | LOG_ERROR(Service_NVDRV, "Size is 0"); |
| 80 | return static_cast<u32>(NvErrCodes::InvalidValue); | 91 | return NvResult::BadValue; |
| 81 | } | 92 | } |
| 82 | 93 | ||
| 83 | params.handle = CreateObject(params.size); | 94 | params.handle = CreateObject(params.size); |
| 84 | 95 | ||
| 85 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 96 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 86 | return 0; | 97 | return NvResult::Success; |
| 87 | } | 98 | } |
| 88 | 99 | ||
| 89 | u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | 100 | NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { |
| 90 | IocAllocParams params; | 101 | IocAllocParams params; |
| 91 | std::memcpy(¶ms, input.data(), sizeof(params)); | 102 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 92 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 103 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 93 | 104 | ||
| 94 | if (!params.handle) { | 105 | if (!params.handle) { |
| 95 | LOG_ERROR(Service_NVDRV, "Handle is 0"); | 106 | LOG_ERROR(Service_NVDRV, "Handle is 0"); |
| 96 | return static_cast<u32>(NvErrCodes::InvalidValue); | 107 | return NvResult::BadValue; |
| 97 | } | 108 | } |
| 98 | 109 | ||
| 99 | if ((params.align - 1) & params.align) { | 110 | if ((params.align - 1) & params.align) { |
| 100 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); | 111 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); |
| 101 | return static_cast<u32>(NvErrCodes::InvalidValue); | 112 | return NvResult::BadValue; |
| 102 | } | 113 | } |
| 103 | 114 | ||
| 104 | const u32 min_alignment = 0x1000; | 115 | const u32 min_alignment = 0x1000; |
| @@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 109 | auto object = GetObject(params.handle); | 120 | auto object = GetObject(params.handle); |
| 110 | if (!object) { | 121 | if (!object) { |
| 111 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 122 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 112 | return static_cast<u32>(NvErrCodes::InvalidValue); | 123 | return NvResult::BadValue; |
| 113 | } | 124 | } |
| 114 | 125 | ||
| 115 | if (object->status == Object::Status::Allocated) { | 126 | if (object->status == Object::Status::Allocated) { |
| 116 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); | 127 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); |
| 117 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 128 | return NvResult::InsufficientMemory; |
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | object->flags = params.flags; | 131 | object->flags = params.flags; |
| @@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 124 | object->status = Object::Status::Allocated; | 135 | object->status = Object::Status::Allocated; |
| 125 | 136 | ||
| 126 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 137 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 127 | return 0; | 138 | return NvResult::Success; |
| 128 | } | 139 | } |
| 129 | 140 | ||
| 130 | u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | 141 | NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 131 | IocGetIdParams params; | 142 | IocGetIdParams params; |
| 132 | std::memcpy(¶ms, input.data(), sizeof(params)); | 143 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 133 | 144 | ||
| @@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 135 | 146 | ||
| 136 | if (!params.handle) { | 147 | if (!params.handle) { |
| 137 | LOG_ERROR(Service_NVDRV, "Handle is zero"); | 148 | LOG_ERROR(Service_NVDRV, "Handle is zero"); |
| 138 | return static_cast<u32>(NvErrCodes::InvalidValue); | 149 | return NvResult::BadValue; |
| 139 | } | 150 | } |
| 140 | 151 | ||
| 141 | auto object = GetObject(params.handle); | 152 | auto object = GetObject(params.handle); |
| 142 | if (!object) { | 153 | if (!object) { |
| 143 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 154 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 144 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 155 | return NvResult::BadValue; |
| 145 | } | 156 | } |
| 146 | 157 | ||
| 147 | params.id = object->id; | 158 | params.id = object->id; |
| 148 | 159 | ||
| 149 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 160 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 150 | return 0; | 161 | return NvResult::Success; |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 154 | IocFromIdParams params; | 165 | IocFromIdParams params; |
| 155 | std::memcpy(¶ms, input.data(), sizeof(params)); | 166 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 156 | 167 | ||
| @@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 160 | [&](const auto& entry) { return entry.second->id == params.id; }); | 171 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 161 | if (itr == handles.end()) { | 172 | if (itr == handles.end()) { |
| 162 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 173 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 163 | return static_cast<u32>(NvErrCodes::InvalidValue); | 174 | return NvResult::BadValue; |
| 164 | } | 175 | } |
| 165 | 176 | ||
| 166 | auto& object = itr->second; | 177 | auto& object = itr->second; |
| 167 | if (object->status != Object::Status::Allocated) { | 178 | if (object->status != Object::Status::Allocated) { |
| 168 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 179 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 169 | return static_cast<u32>(NvErrCodes::InvalidValue); | 180 | return NvResult::BadValue; |
| 170 | } | 181 | } |
| 171 | 182 | ||
| 172 | itr->second->refcount++; | 183 | itr->second->refcount++; |
| @@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 175 | params.handle = itr->first; | 186 | params.handle = itr->first; |
| 176 | 187 | ||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 188 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 178 | return 0; | 189 | return NvResult::Success; |
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | 192 | NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { |
| 182 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; | 193 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; |
| 183 | 194 | ||
| 184 | IocParamParams params; | 195 | IocParamParams params; |
| @@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 189 | auto object = GetObject(params.handle); | 200 | auto object = GetObject(params.handle); |
| 190 | if (!object) { | 201 | if (!object) { |
| 191 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 202 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 192 | return static_cast<u32>(NvErrCodes::InvalidValue); | 203 | return NvResult::BadValue; |
| 193 | } | 204 | } |
| 194 | 205 | ||
| 195 | if (object->status != Object::Status::Allocated) { | 206 | if (object->status != Object::Status::Allocated) { |
| 196 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 207 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 197 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 208 | return NvResult::BadValue; |
| 198 | } | 209 | } |
| 199 | 210 | ||
| 200 | switch (static_cast<ParamTypes>(params.param)) { | 211 | switch (static_cast<ParamTypes>(params.param)) { |
| @@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 216 | } | 227 | } |
| 217 | 228 | ||
| 218 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 229 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 219 | return 0; | 230 | return NvResult::Success; |
| 220 | } | 231 | } |
| 221 | 232 | ||
| 222 | u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | 233 | NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { |
| 223 | // TODO(Subv): These flags are unconfirmed. | 234 | // TODO(Subv): These flags are unconfirmed. |
| 224 | enum FreeFlags { | 235 | enum FreeFlags { |
| 225 | Freed = 0, | 236 | Freed = 0, |
| @@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 234 | auto itr = handles.find(params.handle); | 245 | auto itr = handles.find(params.handle); |
| 235 | if (itr == handles.end()) { | 246 | if (itr == handles.end()) { |
| 236 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 247 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 237 | return static_cast<u32>(NvErrCodes::InvalidValue); | 248 | return NvResult::BadValue; |
| 238 | } | 249 | } |
| 239 | if (!itr->second->refcount) { | 250 | if (!itr->second->refcount) { |
| 240 | LOG_ERROR( | 251 | LOG_ERROR( |
| 241 | Service_NVDRV, | 252 | Service_NVDRV, |
| 242 | "There is no references to this object. The object is already freed. handle={:08X}", | 253 | "There is no references to this object. The object is already freed. handle={:08X}", |
| 243 | params.handle); | 254 | params.handle); |
| 244 | return static_cast<u32>(NvErrCodes::InvalidValue); | 255 | return NvResult::BadValue; |
| 245 | } | 256 | } |
| 246 | 257 | ||
| 247 | itr->second->refcount--; | 258 | itr->second->refcount--; |
| @@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 261 | handles.erase(params.handle); | 272 | handles.erase(params.handle); |
| 262 | 273 | ||
| 263 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 274 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 264 | return 0; | 275 | return NvResult::Success; |
| 265 | } | 276 | } |
| 266 | 277 | ||
| 267 | } // namespace Service::Nvidia::Devices | 278 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 04b9ef540..4484bd79f 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -19,13 +19,15 @@ public: | |||
| 19 | explicit nvmap(Core::System& system); | 19 | explicit nvmap(Core::System& system); |
| 20 | ~nvmap() override; | 20 | ~nvmap() override; |
| 21 | 21 | ||
| 22 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | ||
| 23 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 24 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; | ||
| 25 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 26 | std::vector<u8>& inline_output) override; | ||
| 27 | |||
| 22 | /// Returns the allocated address of an nvmap object given its handle. | 28 | /// Returns the allocated address of an nvmap object given its handle. |
| 23 | VAddr GetObjectAddress(u32 handle) const; | 29 | VAddr GetObjectAddress(u32 handle) const; |
| 24 | 30 | ||
| 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 26 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 27 | IoctlVersion version) override; | ||
| 28 | |||
| 29 | /// Represents an nvmap object. | 31 | /// Represents an nvmap object. |
| 30 | struct Object { | 32 | struct Object { |
| 31 | enum class Status { Created, Allocated }; | 33 | enum class Status { Created, Allocated }; |
| @@ -58,76 +60,68 @@ private: | |||
| 58 | /// Mapping of currently allocated handles to the objects they represent. | 60 | /// Mapping of currently allocated handles to the objects they represent. |
| 59 | std::unordered_map<u32, std::shared_ptr<Object>> handles; | 61 | std::unordered_map<u32, std::shared_ptr<Object>> handles; |
| 60 | 62 | ||
| 61 | enum class IoctlCommand : u32 { | ||
| 62 | Create = 0xC0080101, | ||
| 63 | FromId = 0xC0080103, | ||
| 64 | Alloc = 0xC0200104, | ||
| 65 | Free = 0xC0180105, | ||
| 66 | Param = 0xC00C0109, | ||
| 67 | GetId = 0xC008010E, | ||
| 68 | }; | ||
| 69 | struct IocCreateParams { | 63 | struct IocCreateParams { |
| 70 | // Input | 64 | // Input |
| 71 | u32_le size; | 65 | u32_le size{}; |
| 72 | // Output | 66 | // Output |
| 73 | u32_le handle; | 67 | u32_le handle{}; |
| 74 | }; | 68 | }; |
| 75 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); | 69 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); |
| 76 | 70 | ||
| 77 | struct IocFromIdParams { | 71 | struct IocFromIdParams { |
| 78 | // Input | 72 | // Input |
| 79 | u32_le id; | 73 | u32_le id{}; |
| 80 | // Output | 74 | // Output |
| 81 | u32_le handle; | 75 | u32_le handle{}; |
| 82 | }; | 76 | }; |
| 83 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); | 77 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); |
| 84 | 78 | ||
| 85 | struct IocAllocParams { | 79 | struct IocAllocParams { |
| 86 | // Input | 80 | // Input |
| 87 | u32_le handle; | 81 | u32_le handle{}; |
| 88 | u32_le heap_mask; | 82 | u32_le heap_mask{}; |
| 89 | u32_le flags; | 83 | u32_le flags{}; |
| 90 | u32_le align; | 84 | u32_le align{}; |
| 91 | u8 kind; | 85 | u8 kind{}; |
| 92 | INSERT_PADDING_BYTES(7); | 86 | INSERT_PADDING_BYTES(7); |
| 93 | u64_le addr; | 87 | u64_le addr{}; |
| 94 | }; | 88 | }; |
| 95 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); | 89 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); |
| 96 | 90 | ||
| 97 | struct IocFreeParams { | 91 | struct IocFreeParams { |
| 98 | u32_le handle; | 92 | u32_le handle{}; |
| 99 | INSERT_PADDING_BYTES(4); | 93 | INSERT_PADDING_BYTES(4); |
| 100 | u64_le address; | 94 | u64_le address{}; |
| 101 | u32_le size; | 95 | u32_le size{}; |
| 102 | u32_le flags; | 96 | u32_le flags{}; |
| 103 | }; | 97 | }; |
| 104 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); | 98 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); |
| 105 | 99 | ||
| 106 | struct IocParamParams { | 100 | struct IocParamParams { |
| 107 | // Input | 101 | // Input |
| 108 | u32_le handle; | 102 | u32_le handle{}; |
| 109 | u32_le param; | 103 | u32_le param{}; |
| 110 | // Output | 104 | // Output |
| 111 | u32_le result; | 105 | u32_le result{}; |
| 112 | }; | 106 | }; |
| 113 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); | 107 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); |
| 114 | 108 | ||
| 115 | struct IocGetIdParams { | 109 | struct IocGetIdParams { |
| 116 | // Output | 110 | // Output |
| 117 | u32_le id; | 111 | u32_le id{}; |
| 118 | // Input | 112 | // Input |
| 119 | u32_le handle; | 113 | u32_le handle{}; |
| 120 | }; | 114 | }; |
| 121 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 115 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 122 | 116 | ||
| 123 | u32 CreateObject(u32 size); | 117 | u32 CreateObject(u32 size); |
| 124 | 118 | ||
| 125 | u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); | 119 | NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); |
| 126 | u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); | 120 | NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); |
| 127 | u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); | 121 | NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); |
| 128 | u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); | 122 | NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); |
| 129 | u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); |
| 130 | u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); | 124 | NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output); |
| 131 | }; | 125 | }; |
| 132 | 126 | ||
| 133 | } // namespace Service::Nvidia::Devices | 127 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 88fbfa9b0..f6c38e853 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -23,124 +23,170 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 24 | LOG_DEBUG(Service_NVDRV, "called"); | 24 | LOG_DEBUG(Service_NVDRV, "called"); |
| 25 | 25 | ||
| 26 | if (!is_initialized) { | ||
| 27 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 28 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 26 | const auto& buffer = ctx.ReadBuffer(); | 32 | const auto& buffer = ctx.ReadBuffer(); |
| 27 | std::string device_name(buffer.begin(), buffer.end()); | 33 | const std::string device_name(buffer.begin(), buffer.end()); |
| 34 | DeviceFD fd = nvdrv->Open(device_name); | ||
| 28 | 35 | ||
| 29 | u32 fd = nvdrv->Open(device_name); | ||
| 30 | IPC::ResponseBuilder rb{ctx, 4}; | 36 | IPC::ResponseBuilder rb{ctx, 4}; |
| 31 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 32 | rb.Push<u32>(fd); | 38 | rb.Push<DeviceFD>(fd); |
| 33 | rb.Push<u32>(0); | 39 | rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); |
| 40 | } | ||
| 41 | |||
| 42 | void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { | ||
| 43 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 44 | rb.Push(RESULT_SUCCESS); | ||
| 45 | rb.PushEnum(result); | ||
| 34 | } | 46 | } |
| 35 | 47 | ||
| 36 | void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { | 48 | void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { |
| 37 | IPC::RequestParser rp{ctx}; | 49 | IPC::RequestParser rp{ctx}; |
| 38 | u32 fd = rp.Pop<u32>(); | 50 | const auto fd = rp.Pop<DeviceFD>(); |
| 39 | u32 command = rp.Pop<u32>(); | 51 | const auto command = rp.PopRaw<Ioctl>(); |
| 40 | 52 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | |
| 41 | /// Ioctl 3 has 2 outputs, first in the input params, second is the result | 53 | |
| 42 | std::vector<u8> output(ctx.GetWriteBufferSize(0)); | 54 | if (!is_initialized) { |
| 43 | std::vector<u8> output2; | 55 | ServiceError(ctx, NvResult::NotInitialized); |
| 44 | if (version == IoctlVersion::Version3) { | 56 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); |
| 45 | output2.resize((ctx.GetWriteBufferSize(1))); | 57 | return; |
| 46 | } | 58 | } |
| 47 | 59 | ||
| 48 | /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. | 60 | // Check device |
| 49 | /// KickOfPB uses this | 61 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); |
| 50 | auto input = ctx.ReadBuffer(0); | 62 | const auto input_buffer = ctx.ReadBuffer(0); |
| 51 | 63 | ||
| 52 | std::vector<u8> input2; | 64 | const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); |
| 53 | if (version == IoctlVersion::Version2) { | ||
| 54 | input2 = ctx.ReadBuffer(1); | ||
| 55 | } | ||
| 56 | 65 | ||
| 57 | IoctlCtrl ctrl{}; | 66 | if (command.is_out != 0) { |
| 58 | 67 | ctx.WriteBuffer(output_buffer); | |
| 59 | u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); | ||
| 60 | |||
| 61 | if (ctrl.must_delay) { | ||
| 62 | ctrl.fresh_call = false; | ||
| 63 | ctx.SleepClientThread( | ||
| 64 | "NVServices::DelayedResponse", ctrl.timeout, | ||
| 65 | [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_, | ||
| 66 | Kernel::ThreadWakeupReason reason) { | ||
| 67 | IoctlCtrl ctrl2{ctrl}; | ||
| 68 | std::vector<u8> tmp_output = output; | ||
| 69 | std::vector<u8> tmp_output2 = output2; | ||
| 70 | const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, | ||
| 71 | tmp_output2, ctrl2, version); | ||
| 72 | ctx_.WriteBuffer(tmp_output, 0); | ||
| 73 | if (version == IoctlVersion::Version3) { | ||
| 74 | ctx_.WriteBuffer(tmp_output2, 1); | ||
| 75 | } | ||
| 76 | IPC::ResponseBuilder rb{ctx_, 3}; | ||
| 77 | rb.Push(RESULT_SUCCESS); | ||
| 78 | rb.Push(ioctl_result); | ||
| 79 | }, | ||
| 80 | nvdrv->GetEventWriteable(ctrl.event_id)); | ||
| 81 | } else { | ||
| 82 | ctx.WriteBuffer(output); | ||
| 83 | if (version == IoctlVersion::Version3) { | ||
| 84 | ctx.WriteBuffer(output2, 1); | ||
| 85 | } | ||
| 86 | } | 68 | } |
| 69 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | 70 | IPC::ResponseBuilder rb{ctx, 3}; |
| 88 | rb.Push(RESULT_SUCCESS); | 71 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.Push(result); | 72 | rb.PushEnum(nv_result); |
| 90 | } | ||
| 91 | |||
| 92 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | ||
| 93 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 94 | IoctlBase(ctx, IoctlVersion::Version1); | ||
| 95 | } | 73 | } |
| 96 | 74 | ||
| 97 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { | 75 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { |
| 98 | LOG_DEBUG(Service_NVDRV, "called"); | 76 | IPC::RequestParser rp{ctx}; |
| 99 | IoctlBase(ctx, IoctlVersion::Version2); | 77 | const auto fd = rp.Pop<DeviceFD>(); |
| 78 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 79 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 80 | |||
| 81 | if (!is_initialized) { | ||
| 82 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 83 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 88 | const auto input_inlined_buffer = ctx.ReadBuffer(1); | ||
| 89 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 90 | |||
| 91 | const auto nv_result = | ||
| 92 | nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); | ||
| 93 | |||
| 94 | if (command.is_out != 0) { | ||
| 95 | ctx.WriteBuffer(output_buffer); | ||
| 96 | } | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | rb.PushEnum(nv_result); | ||
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { | 103 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { |
| 103 | LOG_DEBUG(Service_NVDRV, "called"); | 104 | IPC::RequestParser rp{ctx}; |
| 104 | IoctlBase(ctx, IoctlVersion::Version3); | 105 | const auto fd = rp.Pop<DeviceFD>(); |
| 106 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 107 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 108 | |||
| 109 | if (!is_initialized) { | ||
| 110 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 111 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | |||
| 115 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 116 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 117 | std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); | ||
| 118 | |||
| 119 | const auto nv_result = | ||
| 120 | nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); | ||
| 121 | |||
| 122 | if (command.is_out != 0) { | ||
| 123 | ctx.WriteBuffer(output_buffer, 0); | ||
| 124 | ctx.WriteBuffer(output_buffer_inline, 1); | ||
| 125 | } | ||
| 126 | |||
| 127 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 128 | rb.Push(RESULT_SUCCESS); | ||
| 129 | rb.PushEnum(nv_result); | ||
| 105 | } | 130 | } |
| 106 | 131 | ||
| 107 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 132 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| 108 | LOG_DEBUG(Service_NVDRV, "called"); | 133 | LOG_DEBUG(Service_NVDRV, "called"); |
| 109 | 134 | ||
| 110 | IPC::RequestParser rp{ctx}; | 135 | if (!is_initialized) { |
| 111 | u32 fd = rp.Pop<u32>(); | 136 | ServiceError(ctx, NvResult::NotInitialized); |
| 137 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 138 | return; | ||
| 139 | } | ||
| 112 | 140 | ||
| 113 | auto result = nvdrv->Close(fd); | 141 | IPC::RequestParser rp{ctx}; |
| 142 | const auto fd = rp.Pop<DeviceFD>(); | ||
| 143 | const auto result = nvdrv->Close(fd); | ||
| 114 | 144 | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 145 | IPC::ResponseBuilder rb{ctx, 3}; |
| 116 | rb.Push(result); | 146 | rb.Push(RESULT_SUCCESS); |
| 147 | rb.PushEnum(result); | ||
| 117 | } | 148 | } |
| 118 | 149 | ||
| 119 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 150 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 120 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 151 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 121 | 152 | ||
| 153 | is_initialized = true; | ||
| 154 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 3}; | 155 | IPC::ResponseBuilder rb{ctx, 3}; |
| 123 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 124 | rb.Push<u32>(0); | 157 | rb.PushEnum(NvResult::Success); |
| 125 | } | 158 | } |
| 126 | 159 | ||
| 127 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | 160 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { |
| 128 | IPC::RequestParser rp{ctx}; | 161 | IPC::RequestParser rp{ctx}; |
| 129 | u32 fd = rp.Pop<u32>(); | 162 | const auto fd = rp.Pop<DeviceFD>(); |
| 130 | // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 | 163 | const auto event_id = rp.Pop<u32>() & 0x00FF; |
| 131 | u32 event_id = rp.Pop<u32>() & 0x000000FF; | ||
| 132 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); | 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); |
| 133 | 165 | ||
| 134 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 166 | if (!is_initialized) { |
| 135 | rb.Push(RESULT_SUCCESS); | 167 | ServiceError(ctx, NvResult::NotInitialized); |
| 168 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 172 | const auto nv_result = nvdrv->VerifyFD(fd); | ||
| 173 | if (nv_result != NvResult::Success) { | ||
| 174 | LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); | ||
| 175 | ServiceError(ctx, nv_result); | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | |||
| 136 | if (event_id < MaxNvEvents) { | 179 | if (event_id < MaxNvEvents) { |
| 180 | IPC::ResponseBuilder rb{ctx, 3, 1}; | ||
| 181 | rb.Push(RESULT_SUCCESS); | ||
| 137 | auto event = nvdrv->GetEvent(event_id); | 182 | auto event = nvdrv->GetEvent(event_id); |
| 138 | event->Clear(); | 183 | event->Clear(); |
| 139 | rb.PushCopyObjects(event); | 184 | rb.PushCopyObjects(event); |
| 140 | rb.Push<u32>(NvResult::Success); | 185 | rb.PushEnum(NvResult::Success); |
| 141 | } else { | 186 | } else { |
| 142 | rb.Push<u32>(0); | 187 | IPC::ResponseBuilder rb{ctx, 3}; |
| 143 | rb.Push<u32>(NvResult::BadParameter); | 188 | rb.Push(RESULT_SUCCESS); |
| 189 | rb.PushEnum(NvResult::BadParameter); | ||
| 144 | } | 190 | } |
| 145 | } | 191 | } |
| 146 | 192 | ||
| @@ -151,7 +197,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { | |||
| 151 | 197 | ||
| 152 | IPC::ResponseBuilder rb{ctx, 3}; | 198 | IPC::ResponseBuilder rb{ctx, 3}; |
| 153 | rb.Push(RESULT_SUCCESS); | 199 | rb.Push(RESULT_SUCCESS); |
| 154 | rb.Push<u32>(0); | 200 | rb.PushEnum(NvResult::Success); |
| 155 | } | 201 | } |
| 156 | 202 | ||
| 157 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { | 203 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -164,8 +210,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct | |||
| 164 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { | 210 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 211 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 166 | 212 | ||
| 167 | IPC::ResponseBuilder rb{ctx, 2}; | 213 | IPC::ResponseBuilder rb{ctx, 3}; |
| 168 | rb.Push(RESULT_SUCCESS); | 214 | rb.Push(RESULT_SUCCESS); |
| 215 | rb.PushEnum(NvResult::Success); | ||
| 169 | } | 216 | } |
| 170 | 217 | ||
| 171 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | 218 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { |
| @@ -181,7 +228,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 181 | : ServiceFramework(name), nvdrv(std::move(nvdrv)) { | 228 | : ServiceFramework(name), nvdrv(std::move(nvdrv)) { |
| 182 | static const FunctionInfo functions[] = { | 229 | static const FunctionInfo functions[] = { |
| 183 | {0, &NVDRV::Open, "Open"}, | 230 | {0, &NVDRV::Open, "Open"}, |
| 184 | {1, &NVDRV::Ioctl, "Ioctl"}, | 231 | {1, &NVDRV::Ioctl1, "Ioctl"}, |
| 185 | {2, &NVDRV::Close, "Close"}, | 232 | {2, &NVDRV::Close, "Close"}, |
| 186 | {3, &NVDRV::Initialize, "Initialize"}, | 233 | {3, &NVDRV::Initialize, "Initialize"}, |
| 187 | {4, &NVDRV::QueryEvent, "QueryEvent"}, | 234 | {4, &NVDRV::QueryEvent, "QueryEvent"}, |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 72e17a728..e05f905ae 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void Open(Kernel::HLERequestContext& ctx); | 25 | void Open(Kernel::HLERequestContext& ctx); |
| 26 | void Ioctl(Kernel::HLERequestContext& ctx); | 26 | void Ioctl1(Kernel::HLERequestContext& ctx); |
| 27 | void Ioctl2(Kernel::HLERequestContext& ctx); | 27 | void Ioctl2(Kernel::HLERequestContext& ctx); |
| 28 | void Ioctl3(Kernel::HLERequestContext& ctx); | 28 | void Ioctl3(Kernel::HLERequestContext& ctx); |
| 29 | void Close(Kernel::HLERequestContext& ctx); | 29 | void Close(Kernel::HLERequestContext& ctx); |
| @@ -33,11 +33,13 @@ private: | |||
| 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); | 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); |
| 34 | void GetStatus(Kernel::HLERequestContext& ctx); | 34 | void GetStatus(Kernel::HLERequestContext& ctx); |
| 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); |
| 36 | void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); | 36 | |
| 37 | void ServiceError(Kernel::HLERequestContext& ctx, NvResult result); | ||
| 37 | 38 | ||
| 38 | std::shared_ptr<Module> nvdrv; | 39 | std::shared_ptr<Module> nvdrv; |
| 39 | 40 | ||
| 40 | u64 pid{}; | 41 | u64 pid{}; |
| 42 | bool is_initialized{}; | ||
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 43 | } // namespace Service::Nvidia | 45 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 529b03471..3294bc0e7 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include <array> | 3 | #include <array> |
| 4 | #include "common/bit_field.h" | ||
| 4 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 5 | 6 | ||
| 6 | namespace Service::Nvidia { | 7 | namespace Service::Nvidia { |
| 7 | 8 | ||
| 8 | constexpr u32 MaxSyncPoints = 192; | 9 | constexpr u32 MaxSyncPoints = 192; |
| 9 | constexpr u32 MaxNvEvents = 64; | 10 | constexpr u32 MaxNvEvents = 64; |
| 11 | using DeviceFD = s32; | ||
| 12 | |||
| 13 | constexpr DeviceFD INVALID_NVDRV_FD = -1; | ||
| 10 | 14 | ||
| 11 | struct Fence { | 15 | struct Fence { |
| 12 | s32 id; | 16 | s32 id; |
| @@ -20,11 +24,61 @@ struct MultiFence { | |||
| 20 | std::array<Fence, 4> fences; | 24 | std::array<Fence, 4> fences; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | enum NvResult : u32 { | 27 | enum class NvResult : u32 { |
| 24 | Success = 0, | 28 | Success = 0x0, |
| 25 | BadParameter = 4, | 29 | NotImplemented = 0x1, |
| 26 | Timeout = 5, | 30 | NotSupported = 0x2, |
| 27 | ResourceError = 15, | 31 | NotInitialized = 0x3, |
| 32 | BadParameter = 0x4, | ||
| 33 | Timeout = 0x5, | ||
| 34 | InsufficientMemory = 0x6, | ||
| 35 | ReadOnlyAttribute = 0x7, | ||
| 36 | InvalidState = 0x8, | ||
| 37 | InvalidAddress = 0x9, | ||
| 38 | InvalidSize = 0xA, | ||
| 39 | BadValue = 0xB, | ||
| 40 | AlreadyAllocated = 0xD, | ||
| 41 | Busy = 0xE, | ||
| 42 | ResourceError = 0xF, | ||
| 43 | CountMismatch = 0x10, | ||
| 44 | OverFlow = 0x11, | ||
| 45 | InsufficientTransferMemory = 0x1000, | ||
| 46 | InsufficientVideoMemory = 0x10000, | ||
| 47 | BadSurfaceColorScheme = 0x10001, | ||
| 48 | InvalidSurface = 0x10002, | ||
| 49 | SurfaceNotSupported = 0x10003, | ||
| 50 | DispInitFailed = 0x20000, | ||
| 51 | DispAlreadyAttached = 0x20001, | ||
| 52 | DispTooManyDisplays = 0x20002, | ||
| 53 | DispNoDisplaysAttached = 0x20003, | ||
| 54 | DispModeNotSupported = 0x20004, | ||
| 55 | DispNotFound = 0x20005, | ||
| 56 | DispAttachDissallowed = 0x20006, | ||
| 57 | DispTypeNotSupported = 0x20007, | ||
| 58 | DispAuthenticationFailed = 0x20008, | ||
| 59 | DispNotAttached = 0x20009, | ||
| 60 | DispSamePwrState = 0x2000A, | ||
| 61 | DispEdidFailure = 0x2000B, | ||
| 62 | DispDsiReadAckError = 0x2000C, | ||
| 63 | DispDsiReadInvalidResp = 0x2000D, | ||
| 64 | FileWriteFailed = 0x30000, | ||
| 65 | FileReadFailed = 0x30001, | ||
| 66 | EndOfFile = 0x30002, | ||
| 67 | FileOperationFailed = 0x30003, | ||
| 68 | DirOperationFailed = 0x30004, | ||
| 69 | EndOfDirList = 0x30005, | ||
| 70 | ConfigVarNotFound = 0x30006, | ||
| 71 | InvalidConfigVar = 0x30007, | ||
| 72 | LibraryNotFound = 0x30008, | ||
| 73 | SymbolNotFound = 0x30009, | ||
| 74 | MemoryMapFailed = 0x3000A, | ||
| 75 | IoctlFailed = 0x3000F, | ||
| 76 | AccessDenied = 0x30010, | ||
| 77 | DeviceNotFound = 0x30011, | ||
| 78 | KernelDriverNotFound = 0x30012, | ||
| 79 | FileNotFound = 0x30013, | ||
| 80 | PathAlreadyExists = 0x30014, | ||
| 81 | ModuleNotPresent = 0xA000E, | ||
| 28 | }; | 82 | }; |
| 29 | 83 | ||
| 30 | enum class EventState { | 84 | enum class EventState { |
| @@ -34,21 +88,13 @@ enum class EventState { | |||
| 34 | Busy = 3, | 88 | Busy = 3, |
| 35 | }; | 89 | }; |
| 36 | 90 | ||
| 37 | enum class IoctlVersion : u32 { | 91 | union Ioctl { |
| 38 | Version1, | 92 | u32_le raw; |
| 39 | Version2, | 93 | BitField<0, 8, u32> cmd; |
| 40 | Version3, | 94 | BitField<8, 8, u32> group; |
| 41 | }; | 95 | BitField<16, 14, u32> length; |
| 42 | 96 | BitField<30, 1, u32> is_in; | |
| 43 | struct IoctlCtrl { | 97 | BitField<31, 1, u32> is_out; |
| 44 | // First call done to the servioce for services that call itself again after a call. | ||
| 45 | bool fresh_call{true}; | ||
| 46 | // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep | ||
| 47 | bool must_delay{}; | ||
| 48 | // Timeout for the delay | ||
| 49 | s64 timeout{}; | ||
| 50 | // NV Event Id | ||
| 51 | s32 event_id{-1}; | ||
| 52 | }; | 98 | }; |
| 53 | 99 | ||
| 54 | } // namespace Service::Nvidia | 100 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 046a1f28c..bdbbedd0d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -62,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { | |||
| 62 | 62 | ||
| 63 | Module::~Module() = default; | 63 | Module::~Module() = default; |
| 64 | 64 | ||
| 65 | u32 Module::Open(const std::string& device_name) { | 65 | NvResult Module::VerifyFD(DeviceFD fd) const { |
| 66 | ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", | 66 | if (fd < 0) { |
| 67 | device_name); | 67 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 68 | return NvResult::InvalidState; | ||
| 69 | } | ||
| 70 | |||
| 71 | if (open_files.find(fd) == open_files.end()) { | ||
| 72 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 73 | return NvResult::NotImplemented; | ||
| 74 | } | ||
| 75 | |||
| 76 | return NvResult::Success; | ||
| 77 | } | ||
| 78 | |||
| 79 | DeviceFD Module::Open(const std::string& device_name) { | ||
| 80 | if (devices.find(device_name) == devices.end()) { | ||
| 81 | LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); | ||
| 82 | return INVALID_NVDRV_FD; | ||
| 83 | } | ||
| 68 | 84 | ||
| 69 | auto device = devices[device_name]; | 85 | auto device = devices[device_name]; |
| 70 | const u32 fd = next_fd++; | 86 | const DeviceFD fd = next_fd++; |
| 71 | 87 | ||
| 72 | open_files[fd] = std::move(device); | 88 | open_files[fd] = std::move(device); |
| 73 | 89 | ||
| 74 | return fd; | 90 | return fd; |
| 75 | } | 91 | } |
| 76 | 92 | ||
| 77 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 93 | NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 78 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 94 | std::vector<u8>& output) { |
| 79 | IoctlVersion version) { | 95 | if (fd < 0) { |
| 80 | auto itr = open_files.find(fd); | 96 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 81 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 97 | return NvResult::InvalidState; |
| 98 | } | ||
| 82 | 99 | ||
| 83 | auto& device = itr->second; | 100 | const auto itr = open_files.find(fd); |
| 84 | return device->ioctl({command}, input, input2, output, output2, ctrl, version); | 101 | |
| 102 | if (itr == open_files.end()) { | ||
| 103 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 104 | return NvResult::NotImplemented; | ||
| 105 | } | ||
| 106 | |||
| 107 | return itr->second->Ioctl1(command, input, output); | ||
| 85 | } | 108 | } |
| 86 | 109 | ||
| 87 | ResultCode Module::Close(u32 fd) { | 110 | NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 88 | auto itr = open_files.find(fd); | 111 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 89 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 112 | if (fd < 0) { |
| 113 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 114 | return NvResult::InvalidState; | ||
| 115 | } | ||
| 116 | |||
| 117 | const auto itr = open_files.find(fd); | ||
| 118 | |||
| 119 | if (itr == open_files.end()) { | ||
| 120 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 121 | return NvResult::NotImplemented; | ||
| 122 | } | ||
| 123 | |||
| 124 | return itr->second->Ioctl2(command, input, inline_input, output); | ||
| 125 | } | ||
| 126 | |||
| 127 | NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 128 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 129 | if (fd < 0) { | ||
| 130 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 131 | return NvResult::InvalidState; | ||
| 132 | } | ||
| 133 | |||
| 134 | const auto itr = open_files.find(fd); | ||
| 135 | |||
| 136 | if (itr == open_files.end()) { | ||
| 137 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 138 | return NvResult::NotImplemented; | ||
| 139 | } | ||
| 140 | |||
| 141 | return itr->second->Ioctl3(command, input, output, inline_output); | ||
| 142 | } | ||
| 143 | |||
| 144 | NvResult Module::Close(DeviceFD fd) { | ||
| 145 | if (fd < 0) { | ||
| 146 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 147 | return NvResult::InvalidState; | ||
| 148 | } | ||
| 149 | |||
| 150 | const auto itr = open_files.find(fd); | ||
| 151 | |||
| 152 | if (itr == open_files.end()) { | ||
| 153 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 154 | return NvResult::NotImplemented; | ||
| 155 | } | ||
| 90 | 156 | ||
| 91 | open_files.erase(itr); | 157 | open_files.erase(itr); |
| 92 | 158 | ||
| 93 | // TODO(flerovium): return correct result code if operation failed. | 159 | return NvResult::Success; |
| 94 | return RESULT_SUCCESS; | ||
| 95 | } | 160 | } |
| 96 | 161 | ||
| 97 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | 162 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f3d863dac..7654bb026 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -112,14 +112,23 @@ public: | |||
| 112 | return std::static_pointer_cast<T>(itr->second); | 112 | return std::static_pointer_cast<T>(itr->second); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | NvResult VerifyFD(DeviceFD fd) const; | ||
| 116 | |||
| 115 | /// Opens a device node and returns a file descriptor to it. | 117 | /// Opens a device node and returns a file descriptor to it. |
| 116 | u32 Open(const std::string& device_name); | 118 | DeviceFD Open(const std::string& device_name); |
| 119 | |||
| 117 | /// Sends an ioctl command to the specified file descriptor. | 120 | /// Sends an ioctl command to the specified file descriptor. |
| 118 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 121 | NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 119 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 122 | std::vector<u8>& output); |
| 120 | IoctlVersion version); | 123 | |
| 124 | NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 125 | const std::vector<u8>& inline_input, std::vector<u8>& output); | ||
| 126 | |||
| 127 | NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 128 | std::vector<u8>& output, std::vector<u8>& inline_output); | ||
| 129 | |||
| 121 | /// Closes a device file descriptor and returns operation success. | 130 | /// Closes a device file descriptor and returns operation success. |
| 122 | ResultCode Close(u32 fd); | 131 | NvResult Close(DeviceFD fd); |
| 123 | 132 | ||
| 124 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); | 133 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); |
| 125 | 134 | ||
| @@ -132,10 +141,10 @@ private: | |||
| 132 | SyncpointManager syncpoint_manager; | 141 | SyncpointManager syncpoint_manager; |
| 133 | 142 | ||
| 134 | /// Id to use for the next open file descriptor. | 143 | /// Id to use for the next open file descriptor. |
| 135 | u32 next_fd = 1; | 144 | DeviceFD next_fd = 1; |
| 136 | 145 | ||
| 137 | /// Mapping of file descriptors to the devices they reference. | 146 | /// Mapping of file descriptors to the devices they reference. |
| 138 | std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; | 147 | std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; |
| 139 | 148 | ||
| 140 | /// Mapping of device node names to their implementation. | 149 | /// Mapping of device node names to their implementation. |
| 141 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 150 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; |