From ca42578d4ecd9aae22a26bd3bb6a12631f0da9ab Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 8 Mar 2026 15:55:06 -0400 Subject: [PATCH] [nce] Added "tainted" page fault handling inside dual channel --- src/core/arm/nce/arm_nce.cpp | 22 ++++++++++++++++++++-- src/core/arm/nce/arm_nce.h | 10 ++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 807a8ba919..909bdbe046 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -44,6 +44,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) { using namespace Common::Literals; constexpr u32 StackSize = 128_KiB; constexpr u64 SplitPageAccessWindow = 64; +constexpr size_t MaxPreciseAccessPages = 256; [[nodiscard]] constexpr u64 AlignDownPage(u64 addr) { return addr & ~u64{Memory::YUZU_PAGEMASK}; @@ -191,15 +192,18 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi auto& host_ctx = static_cast(raw_context)->uc_mcontext; auto* fpctx = GetFloatingPointState(host_ctx); auto* info = static_cast(raw_info); + auto* parent = guest_ctx->parent; const u64 fault_addr = reinterpret_cast(info->si_addr); const Common::ProcessAddress addr = fault_addr & ~Memory::YUZU_PAGEMASK; const u64 page_offset = fault_addr & Memory::YUZU_PAGEMASK; - auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); - const bool prefer_precise_channel = ShouldUsePreciseAccessChannel(guest_ctx, fault_addr); + auto& memory = parent->m_running_thread->GetOwnerProcess()->GetMemory(); + const bool prefer_precise_channel = ShouldUsePreciseAccessChannel(guest_ctx, fault_addr) || + parent->IsPreciseAccessPage(fault_addr); if (prefer_precise_channel) { if (auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); next_pc) { + parent->MarkPreciseAccessPage(fault_addr); host_ctx.pc = *next_pc; return true; } @@ -220,6 +224,7 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi } if (auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); next_pc) { + parent->MarkPreciseAccessPage(fault_addr); host_ctx.pc = *next_pc; return true; } @@ -236,6 +241,19 @@ void ArmNce::HandleHostAccessFault(int sig, void* raw_info, void* raw_context) { return g_orig_segv_action.sa_sigaction(sig, static_cast(raw_info), raw_context); } +bool ArmNce::IsPreciseAccessPage(u64 addr) const { + const std::scoped_lock lk{m_precise_pages_guard}; + return m_precise_pages.contains(AlignDownPage(addr)); +} + +void ArmNce::MarkPreciseAccessPage(u64 addr) { + const std::scoped_lock lk{m_precise_pages_guard}; + if (m_precise_pages.size() >= MaxPreciseAccessPages) { + m_precise_pages.clear(); + } + m_precise_pages.insert(AlignDownPage(addr)); +} + void ArmNce::LockThread(Kernel::KThread* thread) { auto* thread_params = &thread->GetNativeExecutionParameters(); LockThreadParameters(thread_params); diff --git a/src/core/arm/nce/arm_nce.h b/src/core/arm/nce/arm_nce.h index be9b304c4c..8be293055c 100644 --- a/src/core/arm/nce/arm_nce.h +++ b/src/core/arm/nce/arm_nce.h @@ -1,9 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include +#include #include "core/arm/arm_interface.h" #include "core/arm/nce/guest_context.h" @@ -77,6 +81,9 @@ private: static void HandleHostAlignmentFault(int sig, void* info, void* raw_context); static void HandleHostAccessFault(int sig, void* info, void* raw_context); + bool IsPreciseAccessPage(u64 addr) const; + void MarkPreciseAccessPage(u64 addr); + public: Core::System& m_system; @@ -88,6 +95,9 @@ public: GuestContext m_guest_ctx{}; Kernel::KThread* m_running_thread{}; + mutable std::mutex m_precise_pages_guard{}; + std::unordered_set m_precise_pages{}; + // Stack for signal processing. std::unique_ptr m_stack{}; };