diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 85 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/interface.cpp | 259 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 13 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 3 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv_interface.cpp | 259 | ||||
-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(), ¶ms, 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(¶ms, 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(), ¶ms, 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(¶ms, 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(), ¶ms, 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 |