CPU/Recompiler: Prevent using fastmem when cache is isolated

No point even trying since it's just going to fault.
This commit is contained in:
Connor McLaughlin 2021-04-12 02:08:37 +10:00
parent 922d320523
commit e087e6f3a2
12 changed files with 69 additions and 33 deletions

View file

@ -77,7 +77,7 @@ static std::wstring s_write_directory;
static PVOID s_veh_handle = nullptr; static PVOID s_veh_handle = nullptr;
static bool s_in_crash_handler = false; 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) if (s_in_crash_handler)
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;

View file

@ -307,7 +307,14 @@ CPUFastmemMode GetFastmemMode()
u8* GetFastmemBase() 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<u8*>(m_fastmem_lut);
return nullptr;
} }
void UpdateFastmemViews(CPUFastmemMode mode) void UpdateFastmemViews(CPUFastmemMode mode)
@ -346,7 +353,6 @@ void UpdateFastmemViews(CPUFastmemMode mode)
} }
Log_InfoPrintf("Fastmem base: %p", m_fastmem_base); Log_InfoPrintf("Fastmem base: %p", m_fastmem_base);
CPU::g_state.fastmem_base = m_fastmem_base;
} }
auto MapRAM = [](u32 base_address) { auto MapRAM = [](u32 base_address) {
@ -423,7 +429,6 @@ void UpdateFastmemViews(CPUFastmemMode mode)
Assert(m_fastmem_lut); Assert(m_fastmem_lut);
Log_InfoPrintf("Fastmem base (software): %p", m_fastmem_lut); Log_InfoPrintf("Fastmem base (software): %p", m_fastmem_lut);
CPU::g_state.fastmem_base = reinterpret_cast<u8*>(m_fastmem_lut);
} }
auto MapRAM = [](u32 base_address) { auto MapRAM = [](u32 base_address) {

View file

@ -785,6 +785,7 @@ bool InitializeFastmem()
} }
Bus::UpdateFastmemViews(mode); Bus::UpdateFastmemViews(mode);
CPU::UpdateFastmemBase();
return true; return true;
} }
@ -792,6 +793,7 @@ void ShutdownFastmem()
{ {
Common::PageFaultHandler::RemoveHandler(&s_host_code_map); Common::PageFaultHandler::RemoveHandler(&s_host_code_map);
Bus::UpdateFastmemViews(CPUFastmemMode::Disabled); Bus::UpdateFastmemViews(CPUFastmemMode::Disabled);
CPU::UpdateFastmemBase();
} }
#ifdef WITH_MMAP_FASTMEM #ifdef WITH_MMAP_FASTMEM

View file

@ -99,6 +99,8 @@ void Initialize()
s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC;
s_single_step = false; s_single_step = false;
UpdateFastmemBase();
GTE::Initialize(); GTE::Initialize();
if (g_settings.gpu_pgxp_enable) if (g_settings.gpu_pgxp_enable)
@ -131,6 +133,7 @@ void Reset()
g_state.cop0_regs.cause.bits = 0; g_state.cop0_regs.cause.bits = 0;
ClearICache(); ClearICache();
UpdateFastmemBase();
GTE::Reset(); GTE::Reset();
@ -195,6 +198,14 @@ bool DoState(StateWrapper& sw)
return !sw.HasError(); 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) ALWAYS_INLINE_RELEASE void SetPC(u32 new_pc)
{ {
DebugAssert(Common::IsAlignedPow2(new_pc, 4)); DebugAssert(Common::IsAlignedPow2(new_pc, 4));
@ -1973,14 +1984,6 @@ bool InterpretInstructionPGXP()
return g_state.exception_raised; 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 Recompiler::Thunks
} // namespace CPU } // namespace CPU

View file

@ -94,6 +94,7 @@ void Shutdown();
void Reset(); void Reset();
bool DoState(StateWrapper& sw); bool DoState(StateWrapper& sw);
void ClearICache(); void ClearICache();
void UpdateFastmemBase();
/// Executes interpreter loop. /// Executes interpreter loop.
void Execute(); void Execute();

View file

@ -2433,7 +2433,11 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi)
EmitFunctionCall(nullptr, &PGXP::CPU_MFC0, Value::FromConstantU32(cbi.instruction.bits), value); EmitFunctionCall(nullptr, &PGXP::CPU_MFC0, Value::FromConstantU32(cbi.instruction.bits), value);
m_register_cache.WriteGuestRegisterDelayed(cbi.instruction.r.rt, std::move(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 else
{ {
@ -2465,6 +2469,9 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi)
EmitFunctionCall(nullptr, &PGXP::CPU_MTC0, Value::FromConstantU32(cbi.instruction.bits), value, value); 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 // changing SR[Isc] needs to update fastmem views
if (reg == Cop0Reg::SR && g_settings.IsUsingFastmem()) 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); EmitXor(old_value.host_reg, old_value.host_reg, value);
EmitBranchIfBitClear(old_value.host_reg, RegSize_32, 16, &skip_fastmem_update); EmitBranchIfBitClear(old_value.host_reg, RegSize_32, 16, &skip_fastmem_update);
m_register_cache.InhibitAllocation(); m_register_cache.InhibitAllocation();
EmitFunctionCall(nullptr, &Thunks::UpdateFastmemMapping, m_register_cache.GetCPUPtr()); EmitFunctionCall(nullptr, &UpdateFastmemBase, m_register_cache.GetCPUPtr());
EmitUpdateMembasePointer(); EmitUpdateFastmemBase();
EmitBindLabel(&skip_fastmem_update); EmitBindLabel(&skip_fastmem_update);
m_register_cache.UninhibitAllocation(); m_register_cache.UninhibitAllocation();
} }
@ -2785,12 +2792,15 @@ void CodeGenerator::InitSpeculativeRegs()
{ {
for (u8 i = 0; i < static_cast<u8>(Reg::count); i++) for (u8 i = 0; i < static_cast<u8>(Reg::count); i++)
m_speculative_constants.regs[i] = g_state.regs.r[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() void CodeGenerator::InvalidateSpeculativeValues()
{ {
m_speculative_constants.regs.fill(std::nullopt); m_speculative_constants.regs.fill(std::nullopt);
m_speculative_constants.memory.clear(); m_speculative_constants.memory.clear();
m_speculative_constants.cop0_sr.reset();
} }
CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadReg(Reg reg) CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadReg(Reg reg)
@ -2844,4 +2854,13 @@ void CodeGenerator::SpeculativeWriteMemory(u32 address, SpeculativeValue value)
m_speculative_constants.memory.emplace(address, 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 } // namespace CPU::Recompiler

View file

@ -93,7 +93,7 @@ public:
void EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value); void EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value);
void EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value, void EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value,
bool in_far_code); bool in_far_code);
void EmitUpdateMembasePointer(); void EmitUpdateFastmemBase();
// Unconditional branch to pointer. May allocate a scratch register. // Unconditional branch to pointer. May allocate a scratch register.
void EmitBranch(const void* address, bool allow_scratch = true); void EmitBranch(const void* address, bool allow_scratch = true);
@ -264,6 +264,7 @@ private:
{ {
std::array<SpeculativeValue, static_cast<u8>(Reg::count)> regs; std::array<SpeculativeValue, static_cast<u8>(Reg::count)> regs;
std::unordered_map<PhysicalMemoryAddress, SpeculativeValue> memory; std::unordered_map<PhysicalMemoryAddress, SpeculativeValue> memory;
SpeculativeValue cop0_sr;
}; };
void InitSpeculativeRegs(); void InitSpeculativeRegs();
@ -272,6 +273,7 @@ private:
void SpeculativeWriteReg(Reg reg, SpeculativeValue value); void SpeculativeWriteReg(Reg reg, SpeculativeValue value);
SpeculativeValue SpeculativeReadMemory(u32 address); SpeculativeValue SpeculativeReadMemory(u32 address);
void SpeculativeWriteMemory(VirtualMemoryAddress address, SpeculativeValue value); void SpeculativeWriteMemory(VirtualMemoryAddress address, SpeculativeValue value);
bool SpeculativeIsCacheIsolated();
SpeculativeConstants m_speculative_constants; SpeculativeConstants m_speculative_constants;
}; };

View file

@ -1170,7 +1170,7 @@ Value CodeGenerator::GetFastmemStoreBase()
return val; return val;
} }
void CodeGenerator::EmitUpdateMembasePointer() void CodeGenerator::EmitUpdateFastmemBase()
{ {
if (m_fastmem_load_base_in_register) if (m_fastmem_load_base_in_register)
{ {

View file

@ -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))); m_emit->Ldr(GetFastmemBasePtrReg(), a64::MemOperand(GetCPUPtrReg(), offsetof(State, fastmem_base)));
} }

View file

@ -29,7 +29,7 @@ void CodeGenerator::EmitStoreInterpreterLoadDelay(Reg reg, const Value& value)
Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const Value& address, Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const Value& address,
const SpeculativeValue& address_spec, RegSize size) const SpeculativeValue& address_spec, RegSize size)
{ {
if (address.IsConstant()) if (address.IsConstant() && !SpeculativeIsCacheIsolated())
{ {
TickCount read_ticks; TickCount read_ticks;
void* ptr = GetDirectReadMemoryPointer( void* ptr = GetDirectReadMemoryPointer(
@ -61,17 +61,20 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const
Value result = m_register_cache.AllocateScratch(HostPointerSize); 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 (address_spec)
{ {
if (!use_fastmem) 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 else
{ {
Log_DevPrintf("Non-constant load at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, Log_ProfilePrintf("Non-constant load at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc,
use_fastmem ? "yes" : "no"); use_fastmem ? "yes" : "no");
} }
if (g_settings.IsUsingFastmem() && use_fastmem) 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, void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const Value& address,
const SpeculativeValue& address_spec, const Value& value) const SpeculativeValue& address_spec, const Value& value)
{ {
if (address.IsConstant()) if (address.IsConstant() && !SpeculativeIsCacheIsolated())
{ {
void* ptr = GetDirectWriteMemoryPointer( void* ptr = GetDirectWriteMemoryPointer(
static_cast<u32>(address.constant_value), static_cast<u32>(address.constant_value),
@ -128,17 +131,20 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const
AddPendingCycles(true); 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 (address_spec)
{ {
if (!use_fastmem) 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 else
{ {
Log_DevPrintf("Non-constant store at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc, Log_ProfilePrintf("Non-constant store at 0x%08X, speculative address UNKNOWN, using fastmem = %s", cbi.pc,
use_fastmem ? "yes" : "no"); use_fastmem ? "yes" : "no");
} }
if (g_settings.IsUsingFastmem() && use_fastmem) if (g_settings.IsUsingFastmem() && use_fastmem)

View file

@ -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)]); m_emit->mov(GetFastmemBasePtrReg(), m_emit->qword[GetCPUPtrReg() + offsetof(CPU::State, fastmem_base)]);
} }

View file

@ -32,8 +32,6 @@ void UncheckedWriteMemoryByte(u32 address, u8 value);
void UncheckedWriteMemoryHalfWord(u32 address, u16 value); void UncheckedWriteMemoryHalfWord(u32 address, u16 value);
void UncheckedWriteMemoryWord(u32 address, u32 value); void UncheckedWriteMemoryWord(u32 address, u32 value);
void UpdateFastmemMapping();
} // namespace Recompiler::Thunks } // namespace Recompiler::Thunks
} // namespace CPU } // namespace CPU