mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-04-11 23:00:18 -04:00
DolphinQt: Properly lock CPU before accessing emulated memory
This fixes a problem I was having where using frame advance with the debugger open would frequently cause panic alerts about invalid addresses due to the CPU thread changing MSR.DR while the host thread was trying to access memory. To aid in tracking down all the places where we weren't properly locking the CPU, I've created a new type (in Core.h) that you have to pass as a reference or pointer to functions that require running as the CPU thread.
This commit is contained in:
@@ -118,7 +118,7 @@ std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes
|
||||
|
||||
// Requires s_active_codes_lock
|
||||
// NOTE: Refer to "codehandleronly.s" from Gecko OS.
|
||||
static Installation InstallCodeHandlerLocked()
|
||||
static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
|
||||
{
|
||||
std::string data;
|
||||
if (!File::ReadFileToString(File::GetSysDirectory() + GECKO_CODE_HANDLER, data))
|
||||
@@ -142,16 +142,17 @@ static Installation InstallCodeHandlerLocked()
|
||||
|
||||
// Install code handler
|
||||
for (u32 i = 0; i < data.size(); ++i)
|
||||
PowerPC::HostWrite_U8(data[i], INSTALLER_BASE_ADDRESS + i);
|
||||
PowerPC::HostWrite_U8(guard, data[i], INSTALLER_BASE_ADDRESS + i);
|
||||
|
||||
// Patch the code handler to the current system type (Gamecube/Wii)
|
||||
for (unsigned int h = 0; h < data.length(); h += 4)
|
||||
{
|
||||
// Patch MMIO address
|
||||
if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmio_addr ^ 1) << 8)))
|
||||
if (PowerPC::HostRead_U32(guard, INSTALLER_BASE_ADDRESS + h) ==
|
||||
(0x3f000000u | ((mmio_addr ^ 1) << 8)))
|
||||
{
|
||||
NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", INSTALLER_BASE_ADDRESS + h);
|
||||
PowerPC::HostWrite_U32(0x3f000000u | mmio_addr << 8, INSTALLER_BASE_ADDRESS + h);
|
||||
PowerPC::HostWrite_U32(guard, 0x3f000000u | mmio_addr << 8, INSTALLER_BASE_ADDRESS + h);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,11 +162,11 @@ static Installation InstallCodeHandlerLocked()
|
||||
|
||||
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
|
||||
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
|
||||
PowerPC::HostWrite_U32(MAGIC_GAMEID, INSTALLER_BASE_ADDRESS);
|
||||
PowerPC::HostWrite_U32(guard, MAGIC_GAMEID, INSTALLER_BASE_ADDRESS);
|
||||
|
||||
// Create GCT in memory
|
||||
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address);
|
||||
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4);
|
||||
PowerPC::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address);
|
||||
PowerPC::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address + 4);
|
||||
|
||||
// Each code is 8 bytes (2 words) wide. There is a starter code and an end code.
|
||||
const u32 start_address = codelist_base_address + CODE_SIZE;
|
||||
@@ -188,8 +189,8 @@ static Installation InstallCodeHandlerLocked()
|
||||
|
||||
for (const GeckoCode::Code& code : active_code.codes)
|
||||
{
|
||||
PowerPC::HostWrite_U32(code.address, next_address);
|
||||
PowerPC::HostWrite_U32(code.data, next_address + 4);
|
||||
PowerPC::HostWrite_U32(guard, code.address, next_address);
|
||||
PowerPC::HostWrite_U32(guard, code.data, next_address + 4);
|
||||
next_address += CODE_SIZE;
|
||||
}
|
||||
}
|
||||
@@ -198,12 +199,12 @@ static Installation InstallCodeHandlerLocked()
|
||||
end_address - start_address);
|
||||
|
||||
// Stop code. Tells the handler that this is the end of the list.
|
||||
PowerPC::HostWrite_U32(0xF0000000, next_address);
|
||||
PowerPC::HostWrite_U32(0x00000000, next_address + 4);
|
||||
PowerPC::HostWrite_U32(0, HLE_TRAMPOLINE_ADDRESS);
|
||||
PowerPC::HostWrite_U32(guard, 0xF0000000, next_address);
|
||||
PowerPC::HostWrite_U32(guard, 0x00000000, next_address + 4);
|
||||
PowerPC::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
|
||||
|
||||
// Turn on codes
|
||||
PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7);
|
||||
PowerPC::HostWrite_U8(guard, 1, INSTALLER_BASE_ADDRESS + 7);
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
@@ -235,7 +236,7 @@ void Shutdown()
|
||||
s_code_handler_installed = Installation::Uninstalled;
|
||||
}
|
||||
|
||||
void RunCodeHandler()
|
||||
void RunCodeHandler(const Core::CPUThreadGuard& guard)
|
||||
{
|
||||
if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
|
||||
return;
|
||||
@@ -249,7 +250,7 @@ void RunCodeHandler()
|
||||
// fixed within 1 frame of the last error.
|
||||
if (s_active_codes.empty() || s_code_handler_installed == Installation::Failed)
|
||||
return;
|
||||
s_code_handler_installed = InstallCodeHandlerLocked();
|
||||
s_code_handler_installed = InstallCodeHandlerLocked(guard);
|
||||
|
||||
// A warning was already issued for the install failing
|
||||
if (s_code_handler_installed != Installation::Installed)
|
||||
@@ -273,17 +274,17 @@ void RunCodeHandler()
|
||||
ppc_state.gpr[1] -= 8; // Fake stack frame for codehandler
|
||||
ppc_state.gpr[1] &= 0xFFFFFFF0; // Align stack to 16bytes
|
||||
u32 SP = ppc_state.gpr[1]; // Stack Pointer
|
||||
PowerPC::HostWrite_U32(SP + 8, SP);
|
||||
PowerPC::HostWrite_U32(guard, SP + 8, SP);
|
||||
// SP + 4 is reserved for the codehandler to save LR to the stack.
|
||||
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
|
||||
PowerPC::HostWrite_U32(ppc_state.pc, SP + 12);
|
||||
PowerPC::HostWrite_U32(LR(ppc_state), SP + 16);
|
||||
PowerPC::HostWrite_U32(ppc_state.cr.Get(), SP + 20);
|
||||
PowerPC::HostWrite_U32(guard, SFP, SP + 8); // Real stack frame
|
||||
PowerPC::HostWrite_U32(guard, ppc_state.pc, SP + 12);
|
||||
PowerPC::HostWrite_U32(guard, LR(ppc_state), SP + 16);
|
||||
PowerPC::HostWrite_U32(guard, ppc_state.cr.Get(), SP + 20);
|
||||
// Registers FPR0->13 are volatile
|
||||
for (int i = 0; i < 14; ++i)
|
||||
{
|
||||
PowerPC::HostWrite_U64(ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(guard, ppc_state.ps[i].PS0AsU64(), SP + 24 + 2 * i * sizeof(u64));
|
||||
PowerPC::HostWrite_U64(guard, ppc_state.ps[i].PS1AsU64(), SP + 24 + (2 * i + 1) * sizeof(u64));
|
||||
}
|
||||
DEBUG_LOG_FMT(ACTIONREPLAY,
|
||||
"GeckoCodes: Initiating phantom branch-and-link. "
|
||||
|
||||
Reference in New Issue
Block a user