nvdrv_interface.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // SPDX-FileCopyrightText: 2021 yuzu Emulator Project
  2. // SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. #include "common/logging/log.h"
  5. #include "core/core.h"
  6. #include "core/hle/kernel/k_event.h"
  7. #include "core/hle/kernel/k_readable_event.h"
  8. #include "core/hle/service/ipc_helpers.h"
  9. #include "core/hle/service/nvdrv/nvdata.h"
  10. #include "core/hle/service/nvdrv/nvdrv.h"
  11. #include "core/hle/service/nvdrv/nvdrv_interface.h"
  12. namespace Service::Nvidia {
  13. void NVDRV::Open(HLERequestContext& ctx) {
  14. LOG_DEBUG(Service_NVDRV, "called");
  15. IPC::ResponseBuilder rb{ctx, 4};
  16. rb.Push(ResultSuccess);
  17. if (!is_initialized) {
  18. rb.Push<DeviceFD>(0);
  19. rb.PushEnum(NvResult::NotInitialized);
  20. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  21. return;
  22. }
  23. const auto& buffer = ctx.ReadBuffer();
  24. const std::string device_name(buffer.begin(), buffer.end());
  25. if (device_name == "/dev/nvhost-prof-gpu") {
  26. rb.Push<DeviceFD>(0);
  27. rb.PushEnum(NvResult::NotSupported);
  28. LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production");
  29. return;
  30. }
  31. DeviceFD fd = nvdrv->Open(device_name);
  32. rb.Push<DeviceFD>(fd);
  33. rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
  34. }
  35. void NVDRV::ServiceError(HLERequestContext& ctx, NvResult result) {
  36. IPC::ResponseBuilder rb{ctx, 3};
  37. rb.Push(ResultSuccess);
  38. rb.PushEnum(result);
  39. }
  40. void NVDRV::Ioctl1(HLERequestContext& ctx) {
  41. IPC::RequestParser rp{ctx};
  42. const auto fd = rp.Pop<DeviceFD>();
  43. const auto command = rp.PopRaw<Ioctl>();
  44. LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
  45. if (!is_initialized) {
  46. ServiceError(ctx, NvResult::NotInitialized);
  47. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  48. return;
  49. }
  50. // Check device
  51. output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
  52. const auto input_buffer = ctx.ReadBuffer(0);
  53. const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
  54. if (command.is_out != 0) {
  55. ctx.WriteBuffer(output_buffer);
  56. }
  57. IPC::ResponseBuilder rb{ctx, 3};
  58. rb.Push(ResultSuccess);
  59. rb.PushEnum(nv_result);
  60. }
  61. void NVDRV::Ioctl2(HLERequestContext& ctx) {
  62. IPC::RequestParser rp{ctx};
  63. const auto fd = rp.Pop<DeviceFD>();
  64. const auto command = rp.PopRaw<Ioctl>();
  65. LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
  66. if (!is_initialized) {
  67. ServiceError(ctx, NvResult::NotInitialized);
  68. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  69. return;
  70. }
  71. const auto input_buffer = ctx.ReadBuffer(0);
  72. const auto input_inlined_buffer = ctx.ReadBuffer(1);
  73. output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
  74. const auto nv_result =
  75. nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
  76. if (command.is_out != 0) {
  77. ctx.WriteBuffer(output_buffer);
  78. }
  79. IPC::ResponseBuilder rb{ctx, 3};
  80. rb.Push(ResultSuccess);
  81. rb.PushEnum(nv_result);
  82. }
  83. void NVDRV::Ioctl3(HLERequestContext& ctx) {
  84. IPC::RequestParser rp{ctx};
  85. const auto fd = rp.Pop<DeviceFD>();
  86. const auto command = rp.PopRaw<Ioctl>();
  87. LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
  88. if (!is_initialized) {
  89. ServiceError(ctx, NvResult::NotInitialized);
  90. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  91. return;
  92. }
  93. const auto input_buffer = ctx.ReadBuffer(0);
  94. output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
  95. inline_output_buffer.resize_destructive(ctx.GetWriteBufferSize(1));
  96. const auto nv_result =
  97. nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, inline_output_buffer);
  98. if (command.is_out != 0) {
  99. ctx.WriteBuffer(output_buffer, 0);
  100. ctx.WriteBuffer(inline_output_buffer, 1);
  101. }
  102. IPC::ResponseBuilder rb{ctx, 3};
  103. rb.Push(ResultSuccess);
  104. rb.PushEnum(nv_result);
  105. }
  106. void NVDRV::Close(HLERequestContext& ctx) {
  107. LOG_DEBUG(Service_NVDRV, "called");
  108. if (!is_initialized) {
  109. ServiceError(ctx, NvResult::NotInitialized);
  110. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  111. return;
  112. }
  113. IPC::RequestParser rp{ctx};
  114. const auto fd = rp.Pop<DeviceFD>();
  115. const auto result = nvdrv->Close(fd);
  116. IPC::ResponseBuilder rb{ctx, 3};
  117. rb.Push(ResultSuccess);
  118. rb.PushEnum(result);
  119. }
  120. void NVDRV::Initialize(HLERequestContext& ctx) {
  121. LOG_WARNING(Service_NVDRV, "(STUBBED) called");
  122. is_initialized = true;
  123. IPC::ResponseBuilder rb{ctx, 3};
  124. rb.Push(ResultSuccess);
  125. rb.PushEnum(NvResult::Success);
  126. }
  127. void NVDRV::QueryEvent(HLERequestContext& ctx) {
  128. IPC::RequestParser rp{ctx};
  129. const auto fd = rp.Pop<DeviceFD>();
  130. const auto event_id = rp.Pop<u32>();
  131. if (!is_initialized) {
  132. ServiceError(ctx, NvResult::NotInitialized);
  133. LOG_ERROR(Service_NVDRV, "NvServices is not initialized!");
  134. return;
  135. }
  136. Kernel::KEvent* event = nullptr;
  137. NvResult result = nvdrv->QueryEvent(fd, event_id, event);
  138. if (result == NvResult::Success) {
  139. IPC::ResponseBuilder rb{ctx, 3, 1};
  140. rb.Push(ResultSuccess);
  141. auto& readable_event = event->GetReadableEvent();
  142. rb.PushCopyObjects(readable_event);
  143. rb.PushEnum(NvResult::Success);
  144. } else {
  145. LOG_ERROR(Service_NVDRV, "Invalid event request!");
  146. IPC::ResponseBuilder rb{ctx, 3};
  147. rb.Push(ResultSuccess);
  148. rb.PushEnum(result);
  149. }
  150. }
  151. void NVDRV::SetAruid(HLERequestContext& ctx) {
  152. IPC::RequestParser rp{ctx};
  153. pid = rp.Pop<u64>();
  154. LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
  155. IPC::ResponseBuilder rb{ctx, 3};
  156. rb.Push(ResultSuccess);
  157. rb.PushEnum(NvResult::Success);
  158. }
  159. void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(HLERequestContext& ctx) {
  160. LOG_WARNING(Service_NVDRV, "(STUBBED) called");
  161. IPC::ResponseBuilder rb{ctx, 2};
  162. rb.Push(ResultSuccess);
  163. }
  164. void NVDRV::GetStatus(HLERequestContext& ctx) {
  165. LOG_WARNING(Service_NVDRV, "(STUBBED) called");
  166. IPC::ResponseBuilder rb{ctx, 3};
  167. rb.Push(ResultSuccess);
  168. rb.PushEnum(NvResult::Success);
  169. }
  170. void NVDRV::DumpGraphicsMemoryInfo(HLERequestContext& ctx) {
  171. // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
  172. // retail hardware.
  173. LOG_DEBUG(Service_NVDRV, "called");
  174. IPC::ResponseBuilder rb{ctx, 2};
  175. rb.Push(ResultSuccess);
  176. }
  177. NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
  178. : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
  179. static const FunctionInfo functions[] = {
  180. {0, &NVDRV::Open, "Open"},
  181. {1, &NVDRV::Ioctl1, "Ioctl"},
  182. {2, &NVDRV::Close, "Close"},
  183. {3, &NVDRV::Initialize, "Initialize"},
  184. {4, &NVDRV::QueryEvent, "QueryEvent"},
  185. {5, nullptr, "MapSharedMem"},
  186. {6, &NVDRV::GetStatus, "GetStatus"},
  187. {7, nullptr, "SetAruidForTest"},
  188. {8, &NVDRV::SetAruid, "SetAruid"},
  189. {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
  190. {10, nullptr, "InitializeDevtools"},
  191. {11, &NVDRV::Ioctl2, "Ioctl2"},
  192. {12, &NVDRV::Ioctl3, "Ioctl3"},
  193. {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
  194. "SetGraphicsFirmwareMemoryMarginEnabled"},
  195. };
  196. RegisterHandlers(functions);
  197. }
  198. NVDRV::~NVDRV() = default;
  199. } // namespace Service::Nvidia