From d30b885d713fa2b9393aeb3c515f4d881bf838f2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 1 Nov 2021 15:02:47 +0100 Subject: [PATCH] NVDRV: Implement QueryEvent. --- src/core/hle/service/nvdrv/devices/nvdevice.h | 8 ++++ .../hle/service/nvdrv/devices/nvhost_ctrl.cpp | 23 +++++++++ .../hle/service/nvdrv/devices/nvhost_ctrl.h | 2 + .../service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 20 +++++++- .../service/nvdrv/devices/nvhost_ctrl_gpu.h | 14 +++++- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 26 +++++++++- .../hle/service/nvdrv/devices/nvhost_gpu.h | 13 ++++- src/core/hle/service/nvdrv/nvdrv.cpp | 48 +++++++++---------- src/core/hle/service/nvdrv/nvdrv.h | 6 ++- .../hle/service/nvdrv/nvdrv_interface.cpp | 15 ++---- 10 files changed, 134 insertions(+), 41 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 696e8121e5..204b0e7572 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -11,6 +11,10 @@ namespace Core { class System; } +namespace Kernel { +class KEvent; +} + namespace Service::Nvidia::Devices { /// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to @@ -64,6 +68,10 @@ public: */ virtual void OnClose(DeviceFD fd) = 0; + virtual Kernel::KEvent* QueryEvent(u32 event_id) { + return nullptr; + } + protected: Core::System& system; }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index f2b015c8f4..9b393521aa 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -255,4 +255,27 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v return NvResult::Success; } +Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { + const auto event = SyncpointEventValue{.raw = event_id}; + + const bool allocated = event.event_allocated.Value() != 0; + const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; + if (slot >= MaxNvEvents) { + ASSERT(false); + return nullptr; + } + + const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() + : event.syncpoint_id.Value()}; + + auto lock = events_interface.Lock(); + + if (events_interface.registered[slot] && + events_interface.assigned_syncpt[slot] == syncpoint_id) { + ASSERT(events_interface.events[slot]); + return events_interface.events[slot]; + } + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 0471c09b23..d548a78277 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -28,6 +28,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + union SyncpointEventValue { u32 raw; 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 2b3b7efea7..e353408eb9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -7,10 +7,15 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" +#include "core/hle/service/nvdrv/nvdrv.h" namespace Service::Nvidia::Devices { -nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_) : nvdevice{system_} {} +nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) + : nvdevice{system_}, events_interface{events_interface_} { + error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); + unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); +} nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -286,4 +291,17 @@ NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector& input, std::vector& input, @@ -27,6 +31,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: struct IoctlGpuCharacteristics { u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) @@ -160,6 +166,12 @@ private: NvResult ZBCQueryTable(const std::vector& input, std::vector& output); NvResult FlushL2(const std::vector& input, std::vector& output); NvResult GetGpuTime(const std::vector& input, std::vector& output); + + EventInterface& events_interface; + + // Events + Kernel::KEvent* error_notifier_event; + Kernel::KEvent* unknown_event; }; } // 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 b98e63011f..e87fa59924 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" +#include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/memory.h" #include "video_core/gpu.h" @@ -21,10 +22,16 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi } // namespace nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} { + EventInterface& events_interface_, SyncpointManager& syncpoint_manager_) + : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, events_interface{events_interface_}, + syncpoint_manager{syncpoint_manager_} { channel_fence.id = syncpoint_manager_.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); + sm_exception_breakpoint_int_report_event = + events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); + sm_exception_breakpoint_pause_report_event = + events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); + error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); } nvhost_gpu::~nvhost_gpu() = default; @@ -328,4 +335,19 @@ NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector& input, std::vect return NvResult::Success; } +Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { + switch (event_id) { + case 1: + return sm_exception_breakpoint_int_report_event; + case 2: + return sm_exception_breakpoint_pause_report_event; + case 3: + return error_notifier_event; + default: { + LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + } + } + return nullptr; +} + } // 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 8a9f7775ad..eb4936df0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -15,7 +15,8 @@ namespace Service::Nvidia { class SyncpointManager; -} +class EventInterface; +} // namespace Service::Nvidia namespace Service::Nvidia::Devices { @@ -23,7 +24,7 @@ class nvmap; class nvhost_gpu final : public nvdevice { public: explicit nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_); + EventInterface& events_interface_, SyncpointManager& syncpoint_manager_); ~nvhost_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -36,6 +37,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: enum class CtxObjects : u32_le { Ctx2D = 0x902D, @@ -192,8 +195,14 @@ private: NvResult ChannelSetTimeslice(const std::vector& input, std::vector& output); std::shared_ptr nvmap_dev; + EventInterface& events_interface; SyncpointManager& syncpoint_manager; NvFence channel_fence; + + // Events + Kernel::KEvent* sm_exception_breakpoint_int_report_event; + Kernel::KEvent* sm_exception_breakpoint_pause_report_event; + Kernel::KEvent* error_notifier_event; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index fa259abed2..7c0f89c127 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -96,6 +96,12 @@ u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { return 0; } +Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { + Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); + basic_events.push_back(new_event); + return new_event; +} + void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, Core::System& system) { auto module_ = std::make_shared(system); @@ -119,9 +125,10 @@ Module::Module(Core::System& system) } auto nvmap_dev = std::make_shared(system); devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); - devices["/dev/nvhost-gpu"] = - std::make_shared(system, nvmap_dev, syncpoint_manager); - devices["/dev/nvhost-ctrl-gpu"] = std::make_shared(system); + devices["/dev/nvhost-gpu"] = std::make_shared( + system, nvmap_dev, events_interface, syncpoint_manager); + devices["/dev/nvhost-ctrl-gpu"] = + std::make_shared(system, events_interface); devices["/dev/nvmap"] = nvmap_dev; devices["/dev/nvdisp_disp0"] = std::make_shared(system, nvmap_dev); devices["/dev/nvhost-ctrl"] = @@ -255,31 +262,24 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { } } -Kernel::KEvent* Module::GetEvent(u32 event_id) { - const auto event = Devices::nvhost_ctrl::SyncpointEventValue{.raw = event_id}; - - const bool allocated = event.event_allocated.Value() != 0; - const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; - if (slot >= MaxNvEvents) { - ASSERT(false); - return nullptr; +NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { + if (fd < 0) { + LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); + return NvResult::InvalidState; } - const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() - : event.syncpoint_id.Value()}; + const auto itr = open_files.find(fd); - auto lock = events_interface.Lock(); - - if (events_interface.registered[slot] && - events_interface.assigned_syncpt[slot] == syncpoint_id) { - ASSERT(events_interface.events[slot]); - return events_interface.events[slot]; + if (itr == open_files.end()) { + LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); + return NvResult::NotImplemented; } - // Temporary hack. - events_interface.Create(slot); - events_interface.assigned_syncpt[slot] = syncpoint_id; - ASSERT(false); - return events_interface.events[slot]; + + event = itr->second->QueryEvent(event_id); + if (!event) { + return NvResult::BadParameter; + } + return NvResult::Success; } } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 8ce036508a..be8813c978 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include #include @@ -79,9 +80,12 @@ public: u32 FindFreeEvent(u32 syncpoint_id); + Kernel::KEvent* CreateNonCtrlEvent(std::string name); + private: std::mutex events_mutex; Module& module; + std::vector basic_events; }; class Module final { @@ -118,7 +122,7 @@ public: void SignalSyncpt(const u32 syncpoint_id, const u32 value); - Kernel::KEvent* GetEvent(u32 event_id); + NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); private: friend class EventInterface; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 07883feb2f..81ee28f319 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -173,25 +173,20 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { 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; - } + Kernel::KEvent* event = nullptr; + NvResult result = nvdrv->QueryEvent(fd, event_id, event); - auto* event = nvdrv->GetEvent(event_id); - - if (event) { + if (result == NvResult::Success) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(ResultSuccess); auto& readable_event = event->GetReadableEvent(); rb.PushCopyObjects(readable_event); rb.PushEnum(NvResult::Success); } else { + LOG_ERROR(Service_NVDRV, "Invalid event request!"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(NvResult::BadParameter); + rb.PushEnum(result); } }