From e087e6f3a23a8b2bf411ea0c5269003ba38336e9 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 12 Apr 2021 02:08:37 +1000 Subject: [PATCH] CPU/Recompiler: Prevent using fastmem when cache is isolated No point even trying since it's just going to fault. --- src/common/crash_handler.cpp | 2 +- src/core/bus.cpp | 11 +++++-- src/core/cpu_code_cache.cpp | 2 ++ src/core/cpu_core.cpp | 19 +++++++----- src/core/cpu_core.h | 1 + src/core/cpu_recompiler_code_generator.cpp | 25 ++++++++++++++-- src/core/cpu_recompiler_code_generator.h | 4 ++- .../cpu_recompiler_code_generator_aarch32.cpp | 2 +- .../cpu_recompiler_code_generator_aarch64.cpp | 2 +- .../cpu_recompiler_code_generator_generic.cpp | 30 +++++++++++-------- .../cpu_recompiler_code_generator_x64.cpp | 2 +- src/core/cpu_recompiler_thunks.h | 2 -- 12 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/common/crash_handler.cpp b/src/common/crash_handler.cpp index 72e922323..1db770de6 100644 --- a/src/common/crash_handler.cpp +++ b/src/common/crash_handler.cpp @@ -77,7 +77,7 @@ static std::wstring s_write_directory; static PVOID s_veh_handle = nullptr; static bool s_in_crash_handler = false; -static LONG ExceptionHandler(PEXCEPTION_POINTERS exi) +static LONG NTAPI ExceptionHandler(PEXCEPTION_POINTERS exi) { if (s_in_crash_handler) return EXCEPTION_CONTINUE_SEARCH; diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 3c592a3dc..01d6ff539 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -307,7 +307,14 @@ CPUFastmemMode GetFastmemMode() u8* GetFastmemBase() { - return m_fastmem_base; +#ifdef WITH_MMAP_FASTMEM + if (m_fastmem_mode == CPUFastmemMode::MMap) + return m_fastmem_base; +#endif + if (m_fastmem_mode == CPUFastmemMode::LUT) + return reinterpret_cast(m_fastmem_lut); + + return nullptr; } void UpdateFastmemViews(CPUFastmemMode mode) @@ -346,7 +353,6 @@ void UpdateFastmemViews(CPUFastmemMode mode) } Log_InfoPrintf("Fastmem base: %p", m_fastmem_base); - CPU::g_state.fastmem_base = m_fastmem_base; } auto MapRAM = [](u32 base_address) { @@ -423,7 +429,6 @@ void UpdateFastmemViews(CPUFastmemMode mode) Assert(m_fastmem_lut); Log_InfoPrintf("Fastmem base (software): %p", m_fastmem_lut); - CPU::g_state.fastmem_base = reinterpret_cast(m_fastmem_lut); } auto MapRAM = [](u32 base_address) { diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index f160807c6..9ca527e27 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -785,6 +785,7 @@ bool InitializeFastmem() } Bus::UpdateFastmemViews(mode); + CPU::UpdateFastmemBase(); return true; } @@ -792,6 +793,7 @@ void ShutdownFastmem() { Common::PageFaultHandler::RemoveHandler(&s_host_code_map); Bus::UpdateFastmemViews(CPUFastmemMode::Disabled); + CPU::UpdateFastmemBase(); } #ifdef WITH_MMAP_FASTMEM diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 4c5d7fb0d..05fab21ab 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -99,6 +99,8 @@ void Initialize() s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; s_single_step = false; + UpdateFastmemBase(); + GTE::Initialize(); if (g_settings.gpu_pgxp_enable) @@ -131,6 +133,7 @@ void Reset() g_state.cop0_regs.cause.bits = 0; ClearICache(); + UpdateFastmemBase(); GTE::Reset(); @@ -195,6 +198,14 @@ bool DoState(StateWrapper& sw) return !sw.HasError(); } +void UpdateFastmemBase() +{ + if (g_state.cop0_regs.sr.Isc) + g_state.fastmem_base = nullptr; + else + g_state.fastmem_base = Bus::GetFastmemBase(); +} + ALWAYS_INLINE_RELEASE void SetPC(u32 new_pc) { DebugAssert(Common::IsAlignedPow2(new_pc, 4)); @@ -1973,14 +1984,6 @@ bool InterpretInstructionPGXP() return g_state.exception_raised; } -void UpdateFastmemMapping() -{ - if (g_state.cop0_regs.sr.Isc) - g_state.fastmem_base = nullptr; - else - g_state.fastmem_base = Bus::GetFastmemBase(); -} - } // namespace Recompiler::Thunks } // namespace CPU diff --git a/src/core/cpu_core.h b/src/core/cpu_core.h index 98ecb228f..69b8b9518 100644 --- a/src/core/cpu_core.h +++ b/src/core/cpu_core.h @@ -94,6 +94,7 @@ void Shutdown(); void Reset(); bool DoState(StateWrapper& sw); void ClearICache(); +void UpdateFastmemBase(); /// Executes interpreter loop. void Execute(); diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index c44a6860c..534e21099 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -2433,7 +2433,11 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi) EmitFunctionCall(nullptr, &PGXP::CPU_MFC0, Value::FromConstantU32(cbi.instruction.bits), value); m_register_cache.WriteGuestRegisterDelayed(cbi.instruction.r.rt, std::move(value)); - SpeculativeWriteReg(cbi.instruction.r.rt, std::nullopt); + + if (reg == Cop0Reg::SR) + SpeculativeWriteReg(cbi.instruction.r.rt, m_speculative_constants.cop0_sr); + else + SpeculativeWriteReg(cbi.instruction.r.rt, std::nullopt); } else { @@ -2465,6 +2469,9 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi) EmitFunctionCall(nullptr, &PGXP::CPU_MTC0, Value::FromConstantU32(cbi.instruction.bits), value, value); } + if (reg == Cop0Reg::SR) + m_speculative_constants.cop0_sr = SpeculativeReadReg(cbi.instruction.r.rt); + // changing SR[Isc] needs to update fastmem views if (reg == Cop0Reg::SR && g_settings.IsUsingFastmem()) { @@ -2475,8 +2482,8 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi) EmitXor(old_value.host_reg, old_value.host_reg, value); EmitBranchIfBitClear(old_value.host_reg, RegSize_32, 16, &skip_fastmem_update); m_register_cache.InhibitAllocation(); - EmitFunctionCall(nullptr, &Thunks::UpdateFastmemMapping, m_register_cache.GetCPUPtr()); - EmitUpdateMembasePointer(); + EmitFunctionCall(nullptr, &UpdateFastmemBase, m_register_cache.GetCPUPtr()); + EmitUpdateFastmemBase(); EmitBindLabel(&skip_fastmem_update); m_register_cache.UninhibitAllocation(); } @@ -2785,12 +2792,15 @@ void CodeGenerator::InitSpeculativeRegs() { for (u8 i = 0; i < static_cast(Reg::count); i++) m_speculative_constants.regs[i] = g_state.regs.r[i]; + + m_speculative_constants.cop0_sr = g_state.cop0_regs.sr.bits; } void CodeGenerator::InvalidateSpeculativeValues() { m_speculative_constants.regs.fill(std::nullopt); m_speculative_constants.memory.clear(); + m_speculative_constants.cop0_sr.reset(); } CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadReg(Reg reg) @@ -2844,4 +2854,13 @@ void CodeGenerator::SpeculativeWriteMemory(u32 address, SpeculativeValue value) m_speculative_constants.memory.emplace(address, value); } +bool CodeGenerator::SpeculativeIsCacheIsolated() +{ + if (!m_speculative_constants.cop0_sr.has_value()) + return false; + + const Cop0Registers::SR sr{m_speculative_constants.cop0_sr.value()}; + return sr.Isc; +} + } // namespace CPU::Recompiler diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index 21c007449..c10ceae74 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -93,7 +93,7 @@ public: void EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value); void EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value, bool in_far_code); - void EmitUpdateMembasePointer(); + void EmitUpdateFastmemBase(); // Unconditional branch to pointer. May allocate a scratch register. void EmitBranch(const void* address, bool allow_scratch = true); @@ -264,6 +264,7 @@ private: { std::array(Reg::count)> regs; std::unordered_map memory; + SpeculativeValue cop0_sr; }; void InitSpeculativeRegs(); @@ -272,6 +273,7 @@ private: void SpeculativeWriteReg(Reg reg, SpeculativeValue value); SpeculativeValue SpeculativeReadMemory(u32 address); void SpeculativeWriteMemory(VirtualMemoryAddress address, SpeculativeValue value); + bool SpeculativeIsCacheIsolated(); SpeculativeConstants m_speculative_constants; }; diff --git a/src/core/cpu_recompiler_code_generator_aarch32.cpp b/src/core/cpu_recompiler_code_generator_aarch32.cpp index bbee08222..d37e84ae2 100644 --- a/src/core/cpu_recompiler_code_generator_aarch32.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch32.cpp @@ -1170,7 +1170,7 @@ Value CodeGenerator::GetFastmemStoreBase() return val; } -void CodeGenerator::EmitUpdateMembasePointer() +void CodeGenerator::EmitUpdateFastmemBase() { if (m_fastmem_load_base_in_register) { diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index 1e3664266..04978c80c 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -1728,7 +1728,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, } } -void CodeGenerator::EmitUpdateMembasePointer() +void CodeGenerator::EmitUpdateFastmemBase() { m_emit->Ldr(GetFastmemBasePtrReg(), a64::MemOperand(GetCPUPtrReg(), offsetof(State, fastmem_base))); } diff --git a/src/core/cpu_recompiler_code_generator_generic.cpp b/src/core/cpu_recompiler_code_generator_generic.cpp index ddd4e3346..cf34d7e67 100644 --- a/src/core/cpu_recompiler_code_generator_generic.cpp +++ b/src/core/cpu_recompiler_code_generator_generic.cpp @@ -29,7 +29,7 @@ void CodeGenerator::EmitStoreInterpreterLoadDelay(Reg reg, const Value& value) Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const Value& address, const SpeculativeValue& address_spec, RegSize size) { - if (address.IsConstant()) + if (address.IsConstant() && !SpeculativeIsCacheIsolated()) { TickCount read_ticks; void* ptr = GetDirectReadMemoryPointer( @@ -61,17 +61,20 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const Value result = m_register_cache.AllocateScratch(HostPointerSize); - const bool use_fastmem = address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true; + const bool use_fastmem = + (address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true) && !SpeculativeIsCacheIsolated(); if (address_spec) { if (!use_fastmem) - Log_DevPrintf("Non-constant load at 0x%08X, speculative address 0x%08X, using fastmem = %s", cbi.pc, - *address_spec, use_fastmem ? "yes" : "no"); + { + Log_ProfilePrintf("Non-constant load at 0x%08X, speculative address 0x%08X, using fastmem = %s", cbi.pc, + *address_spec, use_fastmem ? "yes" : "no"); + } } else { - Log_DevPrintf("Non-constant load at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, - use_fastmem ? "yes" : "no"); + Log_ProfilePrintf("Non-constant load at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, + use_fastmem ? "yes" : "no"); } if (g_settings.IsUsingFastmem() && use_fastmem) @@ -113,7 +116,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const Value& address, const SpeculativeValue& address_spec, const Value& value) { - if (address.IsConstant()) + if (address.IsConstant() && !SpeculativeIsCacheIsolated()) { void* ptr = GetDirectWriteMemoryPointer( static_cast(address.constant_value), @@ -128,17 +131,20 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const AddPendingCycles(true); - const bool use_fastmem = address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true; + const bool use_fastmem = + (address_spec ? Bus::CanUseFastmemForAddress(*address_spec) : true) && !SpeculativeIsCacheIsolated(); if (address_spec) { if (!use_fastmem) - Log_DevPrintf("Non-constant store at 0x%08X, speculative address 0x%08X, using fastmem = %s", cbi.pc, - *address_spec, use_fastmem ? "yes" : "no"); + { + Log_ProfilePrintf("Non-constant store at 0x%08X, speculative address 0x%08X, using fastmem = %s", cbi.pc, + *address_spec, use_fastmem ? "yes" : "no"); + } } else { - Log_DevPrintf("Non-constant store at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, - use_fastmem ? "yes" : "no"); + Log_ProfilePrintf("Non-constant store at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, + use_fastmem ? "yes" : "no"); } if (g_settings.IsUsingFastmem() && use_fastmem) diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index d782cac64..b7ec8dce7 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -2313,7 +2313,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, } } -void CodeGenerator::EmitUpdateMembasePointer() +void CodeGenerator::EmitUpdateFastmemBase() { m_emit->mov(GetFastmemBasePtrReg(), m_emit->qword[GetCPUPtrReg() + offsetof(CPU::State, fastmem_base)]); } diff --git a/src/core/cpu_recompiler_thunks.h b/src/core/cpu_recompiler_thunks.h index 400ff9131..cb4171ac6 100644 --- a/src/core/cpu_recompiler_thunks.h +++ b/src/core/cpu_recompiler_thunks.h @@ -32,8 +32,6 @@ void UncheckedWriteMemoryByte(u32 address, u8 value); void UncheckedWriteMemoryHalfWord(u32 address, u16 value); void UncheckedWriteMemoryWord(u32 address, u32 value); -void UpdateFastmemMapping(); - } // namespace Recompiler::Thunks } // namespace CPU