summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp85
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp259
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp13
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h3
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp259
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h (renamed from src/core/hle/service/nvdrv/interface.h)0
6 files changed, 308 insertions, 311 deletions
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 98e6296f1..1403a39d0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -19,26 +19,29 @@
namespace Service::Nvidia::Devices {
namespace {
-// Splice vectors will copy count amount of type T from the input vector into the dst vector.
+// Copies count amount of type T from the input vector into the dst vector.
+// Returns the number of bytes written into dst.
template <typename T>
-std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
- std::size_t offset) {
- if (!dst.empty()) {
- std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
+std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
+ std::size_t offset) {
+ if (dst.empty()) {
+ return 0;
}
- return 0;
+ const size_t bytes_copied = count * sizeof(T);
+ std::memcpy(dst.data(), input.data() + offset, bytes_copied);
+ return bytes_copied;
}
-// Write vectors will write data to the output buffer
+// Writes the data in src to an offset into the dst vector. The offset is specified in bytes
+// Returns the number of bytes written into dst.
template <typename T>
std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
if (src.empty()) {
return 0;
- } else {
- std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
- offset += src.size() * sizeof(T);
- return offset;
}
+ const size_t bytes_copied = src.size() * sizeof(T);
+ std::memcpy(dst.data() + offset, src.data(), bytes_copied);
+ return bytes_copied;
}
} // Anonymous namespace
@@ -62,7 +65,6 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
// Instantiate param buffers
- std::size_t offset = sizeof(IoctlSubmit);
std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count);
std::vector<Reloc> relocs(params.relocation_count);
std::vector<u32> reloc_shifts(params.relocation_count);
@@ -70,13 +72,14 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
std::vector<Fence> fences(params.fence_count);
- // Splice input into their respective buffers
- offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
- offset = SpliceVectors(input, relocs, params.relocation_count, offset);
- offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset);
- offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
- offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset);
- offset = SpliceVectors(input, fences, params.fence_count, offset);
+ // Slice input into their respective buffers
+ std::size_t offset = sizeof(IoctlSubmit);
+ offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
+ offset += SliceVectors(input, relocs, params.relocation_count, offset);
+ offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset);
+ offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
+ offset += SliceVectors(input, wait_checks, params.syncpoint_count, offset);
+ offset += SliceVectors(input, fences, params.fence_count, offset);
auto& gpu = system.GPU();
if (gpu.UseNvdec()) {
@@ -88,35 +91,27 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
}
}
for (const auto& cmd_buffer : command_buffers) {
- auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
+ const auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
- const auto map = FindBufferMap(object->dma_map_addr);
- if (!map) {
- LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
- object->addr, object->dma_map_addr);
- return NvResult::Success;
- }
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
- gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
- cmdlist.size() * sizeof(u32));
+ system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(),
+ cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(cmdlist);
}
if (gpu.UseNvdec()) {
-
fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1);
-
Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}};
gpu.PushCommandBuffer(cmdlist);
}
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
// Some games expect command_buffers to be written back
offset = sizeof(IoctlSubmit);
- offset = WriteVectors(output, command_buffers, offset);
- offset = WriteVectors(output, relocs, offset);
- offset = WriteVectors(output, reloc_shifts, offset);
- offset = WriteVectors(output, syncpt_increments, offset);
- offset = WriteVectors(output, wait_checks, offset);
- offset = WriteVectors(output, fences, offset);
+ offset += WriteVectors(output, command_buffers, offset);
+ offset += WriteVectors(output, relocs, offset);
+ offset += WriteVectors(output, reloc_shifts, offset);
+ offset += WriteVectors(output, syncpt_increments, offset);
+ offset += WriteVectors(output, wait_checks, offset);
+ offset += WriteVectors(output, fences, offset);
return NvResult::Success;
}
@@ -148,14 +143,14 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
- SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
+ SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
auto& gpu = system.GPU();
- for (auto& cmf_buff : cmd_buffer_handles) {
- auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
+ for (auto& cmd_buffer : cmd_buffer_handles) {
+ auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)};
if (!object) {
- LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
+ LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
std::memcpy(output.data(), &params, output.size());
return NvResult::InvalidState;
}
@@ -170,7 +165,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
if (!object->dma_map_addr) {
LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
} else {
- cmf_buff.map_address = object->dma_map_addr;
+ cmd_buffer.map_address = object->dma_map_addr;
AddBufferMap(object->dma_map_addr, object->size, object->addr,
object->status == nvmap::Object::Status::Allocated);
}
@@ -186,14 +181,14 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
- SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
+ SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
auto& gpu = system.GPU();
- for (auto& cmf_buff : cmd_buffer_handles) {
- const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
+ for (auto& cmd_buffer : cmd_buffer_handles) {
+ const auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)};
if (!object) {
- LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
+ LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
std::memcpy(output.data(), &params, output.size());
return NvResult::InvalidState;
}
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
deleted file mode 100644
index e4d495000..000000000
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <cinttypes>
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_readable_event.h"
-#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/k_writable_event.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/service/nvdrv/interface.h"
-#include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
-
-namespace Service::Nvidia {
-
-void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
- nvdrv->SignalSyncpt(syncpoint_id, value);
-}
-
-void NVDRV::Open(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NVDRV, "called");
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
-
- if (!is_initialized) {
- rb.Push<DeviceFD>(0);
- rb.PushEnum(NvResult::NotInitialized);
-
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- const auto& buffer = ctx.ReadBuffer();
- const std::string device_name(buffer.begin(), buffer.end());
-
- if (device_name == "/dev/nvhost-prof-gpu") {
- rb.Push<DeviceFD>(0);
- rb.PushEnum(NvResult::NotSupported);
-
- LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production");
- return;
- }
-
- DeviceFD fd = nvdrv->Open(device_name);
-
- rb.Push<DeviceFD>(fd);
- rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
-}
-
-void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(result);
-}
-
-void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto fd = rp.Pop<DeviceFD>();
- const auto command = rp.PopRaw<Ioctl>();
- LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
-
- if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- // Check device
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
- const auto input_buffer = ctx.ReadBuffer(0);
-
- const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
- if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(nv_result);
-}
-
-void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto fd = rp.Pop<DeviceFD>();
- const auto command = rp.PopRaw<Ioctl>();
- LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
-
- if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- const auto input_buffer = ctx.ReadBuffer(0);
- const auto input_inlined_buffer = ctx.ReadBuffer(1);
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
-
- const auto nv_result =
- nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
- if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(nv_result);
-}
-
-void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto fd = rp.Pop<DeviceFD>();
- const auto command = rp.PopRaw<Ioctl>();
- LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
-
- if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- const auto input_buffer = ctx.ReadBuffer(0);
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
- std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
-
- const auto nv_result =
- nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
- if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer, 0);
- ctx.WriteBuffer(output_buffer_inline, 1);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(nv_result);
-}
-
-void NVDRV::Close(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NVDRV, "called");
-
- if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- IPC::RequestParser rp{ctx};
- const auto fd = rp.Pop<DeviceFD>();
- const auto result = nvdrv->Close(fd);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(result);
-}
-
-void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
-
- is_initialized = true;
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(NvResult::Success);
-}
-
-void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto fd = rp.Pop<DeviceFD>();
- const auto event_id = rp.Pop<u32>() & 0x00FF;
- LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
-
- if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
- LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
- return;
- }
-
- const auto nv_result = nvdrv->VerifyFD(fd);
- if (nv_result != NvResult::Success) {
- LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
- ServiceError(ctx, nv_result);
- return;
- }
-
- if (event_id < MaxNvEvents) {
- IPC::ResponseBuilder rb{ctx, 3, 1};
- rb.Push(ResultSuccess);
- auto& event = nvdrv->GetEvent(event_id);
- event.Clear();
- rb.PushCopyObjects(event);
- rb.PushEnum(NvResult::Success);
- } else {
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(NvResult::BadParameter);
- }
-}
-
-void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- pid = rp.Pop<u64>();
- LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(NvResult::Success);
-}
-
-void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(NvResult::Success);
-}
-
-void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
- // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
- // retail hardware.
- LOG_DEBUG(Service_NVDRV, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
- : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
- static const FunctionInfo functions[] = {
- {0, &NVDRV::Open, "Open"},
- {1, &NVDRV::Ioctl1, "Ioctl"},
- {2, &NVDRV::Close, "Close"},
- {3, &NVDRV::Initialize, "Initialize"},
- {4, &NVDRV::QueryEvent, "QueryEvent"},
- {5, nullptr, "MapSharedMem"},
- {6, &NVDRV::GetStatus, "GetStatus"},
- {7, nullptr, "SetAruidForTest"},
- {8, &NVDRV::SetAruid, "SetAruid"},
- {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
- {10, nullptr, "InitializeDevtools"},
- {11, &NVDRV::Ioctl2, "Ioctl2"},
- {12, &NVDRV::Ioctl3, "Ioctl3"},
- {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
- "SetGraphicsFirmwareMemoryMarginEnabled"},
- };
- RegisterHandlers(functions);
-}
-
-NVDRV::~NVDRV() = default;
-
-} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 74796dce1..ff405099a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -20,8 +20,8 @@
#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "core/hle/service/nvdrv/devices/nvmap.h"
-#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvdrv/nvdrv_interface.h"
#include "core/hle/service/nvdrv/nvmemp.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -39,11 +39,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
nvflinger.SetNVDrvInstance(module_);
}
-Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
- auto& kernel = system.Kernel();
+Module::Module(Core::System& system)
+ : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
for (u32 i = 0; i < MaxNvEvents; i++) {
- events_interface.events[i].event = Kernel::KEvent::Create(kernel);
- events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i));
+ events_interface.events[i].event =
+ service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
events_interface.status[i] = EventState::Free;
events_interface.registered[i] = false;
}
@@ -65,8 +65,7 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
Module::~Module() {
for (u32 i = 0; i < MaxNvEvents; i++) {
- events_interface.events[i].event->Close();
- events_interface.events[i].event = nullptr;
+ service_context.CloseEvent(events_interface.events[i].event);
}
}
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a43ceb7ae..e2a1dde5b 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -9,6 +9,7 @@
#include <vector>
#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/hle/service/service.h"
@@ -154,6 +155,8 @@ private:
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
EventInterface events_interface;
+
+ KernelHelpers::ServiceContext service_context;
};
/// Registers all NVDRV services with the specified service manager.
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
new file mode 100644
index 000000000..d61fb73dc
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -0,0 +1,259 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cinttypes>
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_writable_event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/nvdrv/nvdata.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvdrv/nvdrv_interface.h"
+
+namespace Service::Nvidia {
+
+void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
+ nvdrv->SignalSyncpt(syncpoint_id, value);
+}
+
+void NVDRV::Open(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NVDRV, "called");
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+
+ if (!is_initialized) {
+ rb.Push<DeviceFD>(0);
+ rb.PushEnum(NvResult::NotInitialized);
+
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ const auto& buffer = ctx.ReadBuffer();
+ const std::string device_name(buffer.begin(), buffer.end());
+
+ if (device_name == "/dev/nvhost-prof-gpu") {
+ rb.Push<DeviceFD>(0);
+ rb.PushEnum(NvResult::NotSupported);
+
+ LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production");
+ return;
+ }
+
+ DeviceFD fd = nvdrv->Open(device_name);
+
+ rb.Push<DeviceFD>(fd);
+ rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
+}
+
+void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(result);
+}
+
+void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto fd = rp.Pop<DeviceFD>();
+ const auto command = rp.PopRaw<Ioctl>();
+ LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
+
+ if (!is_initialized) {
+ ServiceError(ctx, NvResult::NotInitialized);
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ // Check device
+ std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
+ const auto input_buffer = ctx.ReadBuffer(0);
+
+ const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
+ if (command.is_out != 0) {
+ ctx.WriteBuffer(output_buffer);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(nv_result);
+}
+
+void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto fd = rp.Pop<DeviceFD>();
+ const auto command = rp.PopRaw<Ioctl>();
+ LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
+
+ if (!is_initialized) {
+ ServiceError(ctx, NvResult::NotInitialized);
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ const auto input_buffer = ctx.ReadBuffer(0);
+ const auto input_inlined_buffer = ctx.ReadBuffer(1);
+ std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
+
+ const auto nv_result =
+ nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
+ if (command.is_out != 0) {
+ ctx.WriteBuffer(output_buffer);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(nv_result);
+}
+
+void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto fd = rp.Pop<DeviceFD>();
+ const auto command = rp.PopRaw<Ioctl>();
+ LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
+
+ if (!is_initialized) {
+ ServiceError(ctx, NvResult::NotInitialized);
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ const auto input_buffer = ctx.ReadBuffer(0);
+ std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
+ std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
+
+ const auto nv_result =
+ nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
+ if (command.is_out != 0) {
+ ctx.WriteBuffer(output_buffer, 0);
+ ctx.WriteBuffer(output_buffer_inline, 1);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(nv_result);
+}
+
+void NVDRV::Close(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NVDRV, "called");
+
+ if (!is_initialized) {
+ ServiceError(ctx, NvResult::NotInitialized);
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ IPC::RequestParser rp{ctx};
+ const auto fd = rp.Pop<DeviceFD>();
+ const auto result = nvdrv->Close(fd);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(result);
+}
+
+void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ is_initialized = true;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(NvResult::Success);
+}
+
+void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto fd = rp.Pop<DeviceFD>();
+ const auto event_id = rp.Pop<u32>() & 0x00FF;
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
+
+ if (!is_initialized) {
+ ServiceError(ctx, NvResult::NotInitialized);
+ LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
+ return;
+ }
+
+ const auto nv_result = nvdrv->VerifyFD(fd);
+ if (nv_result != NvResult::Success) {
+ LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
+ ServiceError(ctx, nv_result);
+ return;
+ }
+
+ if (event_id < MaxNvEvents) {
+ IPC::ResponseBuilder rb{ctx, 3, 1};
+ rb.Push(ResultSuccess);
+ auto& event = nvdrv->GetEvent(event_id);
+ event.Clear();
+ rb.PushCopyObjects(event);
+ rb.PushEnum(NvResult::Success);
+ } else {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(NvResult::BadParameter);
+ }
+}
+
+void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ pid = rp.Pop<u64>();
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(NvResult::Success);
+}
+
+void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(NvResult::Success);
+}
+
+void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
+ // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
+ // retail hardware.
+ LOG_DEBUG(Service_NVDRV, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
+ : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
+ static const FunctionInfo functions[] = {
+ {0, &NVDRV::Open, "Open"},
+ {1, &NVDRV::Ioctl1, "Ioctl"},
+ {2, &NVDRV::Close, "Close"},
+ {3, &NVDRV::Initialize, "Initialize"},
+ {4, &NVDRV::QueryEvent, "QueryEvent"},
+ {5, nullptr, "MapSharedMem"},
+ {6, &NVDRV::GetStatus, "GetStatus"},
+ {7, nullptr, "SetAruidForTest"},
+ {8, &NVDRV::SetAruid, "SetAruid"},
+ {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
+ {10, nullptr, "InitializeDevtools"},
+ {11, &NVDRV::Ioctl2, "Ioctl2"},
+ {12, &NVDRV::Ioctl3, "Ioctl3"},
+ {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
+ "SetGraphicsFirmwareMemoryMarginEnabled"},
+ };
+ RegisterHandlers(functions);
+}
+
+NVDRV::~NVDRV() = default;
+
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h
index 0e764c53f..0e764c53f 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h