diff options
| author | 2020-11-26 01:27:24 -0800 | |
|---|---|---|
| committer | 2020-11-26 01:27:24 -0800 | |
| commit | 322349e8cc948d069f62a85a0c09a689c3e31796 (patch) | |
| tree | b11cb630a78fba7e611045462425ce929429a40c | |
| parent | Merge pull request #4981 from ogniK5377/ioctl-ctrl (diff) | |
| parent | nvdrv, video_core: Don't index out of bounds when given invalid syncpoint ID (diff) | |
| download | yuzu-322349e8cc948d069f62a85a0c09a689c3e31796.tar.gz yuzu-322349e8cc948d069f62a85a0c09a689c3e31796.tar.xz yuzu-322349e8cc948d069f62a85a0c09a689c3e31796.zip | |
Merge pull request #4975 from comex/invalid-syncpoint-id
nvdrv, video_core: Don't index out of bounds when given invalid syncpoint ID
| -rw-r--r-- | src/core/hle/service/nvdrv/syncpoint_manager.h | 4 | ||||
| -rw-r--r-- | src/video_core/gpu.cpp | 29 |
2 files changed, 20 insertions, 13 deletions
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h index 4168b6c7e..d395c5d0b 100644 --- a/src/core/hle/service/nvdrv/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/syncpoint_manager.h | |||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | * @returns The lower bound for the specified syncpoint. | 37 | * @returns The lower bound for the specified syncpoint. |
| 38 | */ | 38 | */ |
| 39 | u32 GetSyncpointMin(u32 syncpoint_id) const { | 39 | u32 GetSyncpointMin(u32 syncpoint_id) const { |
| 40 | return syncpoints[syncpoint_id].min.load(std::memory_order_relaxed); | 40 | return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| @@ -46,7 +46,7 @@ public: | |||
| 46 | * @returns The upper bound for the specified syncpoint. | 46 | * @returns The upper bound for the specified syncpoint. |
| 47 | */ | 47 | */ |
| 48 | u32 GetSyncpointMax(u32 syncpoint_id) const { | 48 | u32 GetSyncpointMax(u32 syncpoint_id) const { |
| 49 | return syncpoints[syncpoint_id].max.load(std::memory_order_relaxed); | 49 | return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /** | 52 | /** |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index ebd149c3a..e91f52938 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -95,22 +95,29 @@ void GPU::WaitFence(u32 syncpoint_id, u32 value) { | |||
| 95 | if (!is_async) { | 95 | if (!is_async) { |
| 96 | return; | 96 | return; |
| 97 | } | 97 | } |
| 98 | if (syncpoint_id == UINT32_MAX) { | ||
| 99 | // TODO: Research what this does. | ||
| 100 | LOG_ERROR(HW_GPU, "Waiting for syncpoint -1 not implemented"); | ||
| 101 | return; | ||
| 102 | } | ||
| 98 | MICROPROFILE_SCOPE(GPU_wait); | 103 | MICROPROFILE_SCOPE(GPU_wait); |
| 99 | std::unique_lock lock{sync_mutex}; | 104 | std::unique_lock lock{sync_mutex}; |
| 100 | sync_cv.wait(lock, [=, this] { return syncpoints[syncpoint_id].load() >= value; }); | 105 | sync_cv.wait(lock, [=, this] { return syncpoints.at(syncpoint_id).load() >= value; }); |
| 101 | } | 106 | } |
| 102 | 107 | ||
| 103 | void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | 108 | void GPU::IncrementSyncPoint(const u32 syncpoint_id) { |
| 104 | syncpoints[syncpoint_id]++; | 109 | auto& syncpoint = syncpoints.at(syncpoint_id); |
| 110 | syncpoint++; | ||
| 105 | std::lock_guard lock{sync_mutex}; | 111 | std::lock_guard lock{sync_mutex}; |
| 106 | sync_cv.notify_all(); | 112 | sync_cv.notify_all(); |
| 107 | if (!syncpt_interrupts[syncpoint_id].empty()) { | 113 | auto& interrupt = syncpt_interrupts.at(syncpoint_id); |
| 108 | u32 value = syncpoints[syncpoint_id].load(); | 114 | if (!interrupt.empty()) { |
| 109 | auto it = syncpt_interrupts[syncpoint_id].begin(); | 115 | u32 value = syncpoint.load(); |
| 110 | while (it != syncpt_interrupts[syncpoint_id].end()) { | 116 | auto it = interrupt.begin(); |
| 117 | while (it != interrupt.end()) { | ||
| 111 | if (value >= *it) { | 118 | if (value >= *it) { |
| 112 | TriggerCpuInterrupt(syncpoint_id, *it); | 119 | TriggerCpuInterrupt(syncpoint_id, *it); |
| 113 | it = syncpt_interrupts[syncpoint_id].erase(it); | 120 | it = interrupt.erase(it); |
| 114 | continue; | 121 | continue; |
| 115 | } | 122 | } |
| 116 | it++; | 123 | it++; |
| @@ -119,22 +126,22 @@ void GPU::IncrementSyncPoint(const u32 syncpoint_id) { | |||
| 119 | } | 126 | } |
| 120 | 127 | ||
| 121 | u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { | 128 | u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { |
| 122 | return syncpoints[syncpoint_id].load(); | 129 | return syncpoints.at(syncpoint_id).load(); |
| 123 | } | 130 | } |
| 124 | 131 | ||
| 125 | void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | 132 | void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) { |
| 126 | auto& interrupt = syncpt_interrupts[syncpoint_id]; | 133 | auto& interrupt = syncpt_interrupts.at(syncpoint_id); |
| 127 | bool contains = std::any_of(interrupt.begin(), interrupt.end(), | 134 | bool contains = std::any_of(interrupt.begin(), interrupt.end(), |
| 128 | [value](u32 in_value) { return in_value == value; }); | 135 | [value](u32 in_value) { return in_value == value; }); |
| 129 | if (contains) { | 136 | if (contains) { |
| 130 | return; | 137 | return; |
| 131 | } | 138 | } |
| 132 | syncpt_interrupts[syncpoint_id].emplace_back(value); | 139 | interrupt.emplace_back(value); |
| 133 | } | 140 | } |
| 134 | 141 | ||
| 135 | bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) { | 142 | bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) { |
| 136 | std::lock_guard lock{sync_mutex}; | 143 | std::lock_guard lock{sync_mutex}; |
| 137 | auto& interrupt = syncpt_interrupts[syncpoint_id]; | 144 | auto& interrupt = syncpt_interrupts.at(syncpoint_id); |
| 138 | const auto iter = | 145 | const auto iter = |
| 139 | std::find_if(interrupt.begin(), interrupt.end(), | 146 | std::find_if(interrupt.begin(), interrupt.end(), |
| 140 | [value](u32 interrupt_value) { return value == interrupt_value; }); | 147 | [value](u32 interrupt_value) { return value == interrupt_value; }); |