Fernando Sahmkow 4 лет назад
Родитель
Сommit
d30b885d71

+ 8 - 0
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;
 };

+ 23 - 0
src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp

@@ -255,4 +255,27 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& 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<u32>(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

+ 2 - 0
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;
 

+ 19 - 1
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<u8>& input,
@@ -286,4 +291,17 @@ NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u
     return NvResult::Success;
 }
 
+Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {
+    switch (event_id) {
+    case 1:
+        return error_notifier_event;
+    case 2:
+        return unknown_event;
+    default: {
+        LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
+    }
+    }
+    return nullptr;
+}
+
 } // namespace Service::Nvidia::Devices

+ 13 - 1
src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h

@@ -10,11 +10,15 @@
 #include "common/swap.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
 
+namespace Service::Nvidia {
+class EventInterface;
+}
+
 namespace Service::Nvidia::Devices {
 
 class nvhost_ctrl_gpu final : public nvdevice {
 public:
-    explicit nvhost_ctrl_gpu(Core::System& system_);
+    explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_);
     ~nvhost_ctrl_gpu() override;
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& 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<u8>& input, std::vector<u8>& output);
     NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
+
+    EventInterface& events_interface;
+
+    // Events
+    Kernel::KEvent* error_notifier_event;
+    Kernel::KEvent* unknown_event;
 };
 
 } // namespace Service::Nvidia::Devices

+ 24 - 2
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> 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<u8>& 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

+ 11 - 2
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> nvmap_dev_,
-                        SyncpointManager& syncpoint_manager_);
+                        EventInterface& events_interface_, SyncpointManager& syncpoint_manager_);
     ~nvhost_gpu() override;
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& 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<u8>& input, std::vector<u8>& output);
 
     std::shared_ptr<nvmap> 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

+ 23 - 23
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<Module>(system);
@@ -119,9 +125,10 @@ Module::Module(Core::System& system)
     }
     auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
     devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev);
-    devices["/dev/nvhost-gpu"] =
-        std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager);
-    devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system);
+    devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(
+        system, nvmap_dev, events_interface, syncpoint_manager);
+    devices["/dev/nvhost-ctrl-gpu"] =
+        std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
     devices["/dev/nvmap"] = nvmap_dev;
     devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(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<u32>(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 (itr == open_files.end()) {
+        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
+        return NvResult::NotImplemented;
+    }
 
-    if (events_interface.registered[slot] &&
-        events_interface.assigned_syncpt[slot] == syncpoint_id) {
-        ASSERT(events_interface.events[slot]);
-        return events_interface.events[slot];
+    event = itr->second->QueryEvent(event_id);
+    if (!event) {
+        return NvResult::BadParameter;
     }
-    // Temporary hack.
-    events_interface.Create(slot);
-    events_interface.assigned_syncpt[slot] = syncpoint_id;
-    ASSERT(false);
-    return events_interface.events[slot];
+    return NvResult::Success;
 }
 
 } // namespace Service::Nvidia

+ 5 - 1
src/core/hle/service/nvdrv/nvdrv.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <memory>
+#include <string>
 #include <unordered_map>
 #include <vector>
 
@@ -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<Kernel::KEvent*> 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;

+ 5 - 10
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;
-    }
-
-    auto* event = nvdrv->GetEvent(event_id);
+    Kernel::KEvent* event = nullptr;
+    NvResult result = nvdrv->QueryEvent(fd, event_id, event);
 
-    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);
     }
 }