aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 16:35:21 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 16:57:51 -0400
commitaffa8969acb3f1fe32933a79b7b1e8612e3afd44 (patch)
tree168a8ab0f94331a3f81154faf06c7f4cb94999bb /src/video_core
parentca524c9aa883abc4d1c5aeb8aa4d2f9eb0b4225c (diff)
nx2: ignore syncpoint signals past the syncpoint table
The 3D engine's sync method and the puller's fence action take a syncpoint id from the command list and signal it, but the syncpoint manager has 192 syncpoints and does not check the index. Command words read wrong (Splatoon Raiders on Linux runs 3D engine commands as puller methods 0x10-0x3F just before) made Maxwell3D signal a syncpoint past the table: SyncpointManager::Increment walked memory after its action lists as a list and crashed on a null link (SIGSEGV reading 0x10). Builds 49 and 50 both crashed this way under WSL. FenceManager now drops such signals with an error, for every engine that signals.
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/fence_manager.h8
-rw-r--r--src/video_core/host1x/syncpoint_manager.h4
2 files changed, 10 insertions, 2 deletions
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 61c9844cf2..d9f0ac2837 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -18,6 +18,7 @@
#include <queue>
#include "common/common_types.h"
+#include "common/logging.h"
#include "common/settings.h"
#include "common/thread.h"
#include "video_core/delayed_destruction_ring.h"
@@ -123,6 +124,13 @@ public:
}
void SignalSyncPoint(u32 value) {
+ // The id comes from a command list (the 3D engine's sync method, the puller's fence
+ // action). Past the syncpoint table, the increment would walk memory after it as an
+ // action list; command words read wrong carry any id (Splatoon Raiders on Linux).
+ if (value >= Tegra::Host1x::SyncpointManager::NUM_MAX_SYNCPOINTS) {
+ LOG_ERROR(HW_GPU, "Signal of syncpoint {} past the table, ignored", value);
+ return;
+ }
syncpoint_manager.IncrementGuest(value);
std::function<void()> func([this, value] { syncpoint_manager.IncrementHost(value); });
SignalFence(std::move(func));
diff --git a/src/video_core/host1x/syncpoint_manager.h b/src/video_core/host1x/syncpoint_manager.h
index 847ed20c8d..d6e65af3eb 100644
--- a/src/video_core/host1x/syncpoint_manager.h
+++ b/src/video_core/host1x/syncpoint_manager.h
@@ -18,6 +18,8 @@ namespace Host1x {
class SyncpointManager {
public:
+ static constexpr size_t NUM_MAX_SYNCPOINTS = 192;
+
u32 GetGuestSyncpointValue(u32 id) const {
return syncpoints_guest[id].load(std::memory_order_acquire);
}
@@ -78,8 +80,6 @@ private:
void Wait(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv, u32 expected_value);
- static constexpr size_t NUM_MAX_SYNCPOINTS = 192;
-
std::array<std::atomic<u32>, NUM_MAX_SYNCPOINTS> syncpoints_guest{};
std::array<std::atomic<u32>, NUM_MAX_SYNCPOINTS> syncpoints_host{};