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 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;

View file

@ -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<u8*>(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<u8*>(m_fastmem_lut);
}
auto MapRAM = [](u32 base_address) {

View file

@ -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

View file

@ -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

View file

@ -94,6 +94,7 @@ void Shutdown();
void Reset();
bool DoState(StateWrapper& sw);
void ClearICache();
void UpdateFastmemBase();
/// Executes interpreter loop.
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);
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<u8>(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

View file

@ -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<SpeculativeValue, static_cast<u8>(Reg::count)> regs;
std::unordered_map<PhysicalMemoryAddress, SpeculativeValue> 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;
};

View file

@ -1170,7 +1170,7 @@ Value CodeGenerator::GetFastmemStoreBase()
return val;
}
void CodeGenerator::EmitUpdateMembasePointer()
void CodeGenerator::EmitUpdateFastmemBase()
{
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)));
}

View file

@ -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<u32>(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)

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)]);
}

View file

@ -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