From 7cecb28bdf6443362a6ab20e0042ddb3b407ebec Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 12 Feb 2023 11:07:11 +0100 Subject: [PATCH 1/2] 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. --- Source/Core/Common/Debug/CodeTrace.cpp | 15 +- Source/Core/Common/Debug/CodeTrace.h | 10 +- Source/Core/Common/Debug/MemoryPatches.cpp | 41 ++-- Source/Core/Common/Debug/MemoryPatches.h | 27 ++- Source/Core/Common/Debug/Threads.h | 11 +- Source/Core/Common/DebugInterface.h | 61 ++++-- Source/Core/Common/SymbolDB.h | 7 +- Source/Core/Core/ActionReplay.cpp | 96 ++++----- Source/Core/Core/ActionReplay.h | 7 +- Source/Core/Core/Boot/Boot.cpp | 34 ++-- Source/Core/Core/Boot/Boot.h | 24 ++- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 60 +++--- Source/Core/Core/Boot/DolReader.h | 2 +- Source/Core/Core/Boot/ElfReader.cpp | 4 +- Source/Core/Core/Boot/ElfReader.h | 2 +- Source/Core/Core/CheatSearch.cpp | 75 ++++--- Source/Core/Core/CheatSearch.h | 13 +- Source/Core/Core/ConfigManager.cpp | 4 +- Source/Core/Core/ConfigManager.h | 7 +- Source/Core/Core/Core.cpp | 31 ++- Source/Core/Core/Core.h | 27 +++ .../Core/Core/Debugger/Debugger_SymbolMap.cpp | 31 +-- .../Core/Core/Debugger/Debugger_SymbolMap.h | 9 +- Source/Core/Core/Debugger/OSThread.cpp | 111 ++++++----- Source/Core/Core/Debugger/OSThread.h | 21 +- .../Core/Core/Debugger/PPCDebugInterface.cpp | 126 ++++++------ Source/Core/Core/Debugger/PPCDebugInterface.h | 48 +++-- Source/Core/Core/Debugger/RSO.cpp | 188 +++++++++--------- Source/Core/Core/Debugger/RSO.h | 49 +++-- Source/Core/Core/GeckoCode.cpp | 45 +++-- Source/Core/Core/GeckoCode.h | 7 +- Source/Core/Core/HLE/HLE.cpp | 4 +- Source/Core/Core/HLE/HLE.h | 7 +- Source/Core/Core/HLE/HLE_Misc.cpp | 24 +-- Source/Core/Core/HLE/HLE_Misc.h | 13 +- Source/Core/Core/HLE/HLE_OS.cpp | 98 ++++----- Source/Core/Core/HLE/HLE_OS.h | 21 +- Source/Core/Core/HLE/HLE_VarArgs.cpp | 22 +- Source/Core/Core/HLE/HLE_VarArgs.h | 41 ++-- Source/Core/Core/HW/AddressSpace.cpp | 184 ++++++++++------- Source/Core/Core/HW/AddressSpace.h | 30 +-- Source/Core/Core/IOS/IOS.cpp | 6 +- Source/Core/Core/IOS/MIOS.cpp | 10 +- Source/Core/Core/MemoryWatcher.cpp | 14 +- Source/Core/Core/MemoryWatcher.h | 11 +- Source/Core/Core/PatchEngine.cpp | 50 +++-- Source/Core/Core/PowerPC/Expression.cpp | 53 +++-- Source/Core/Core/PowerPC/Expression.h | 5 + Source/Core/Core/PowerPC/GDBStub.cpp | 21 +- .../Core/PowerPC/Interpreter/Interpreter.cpp | 10 +- .../Interpreter/Interpreter_Branch.cpp | 7 +- Source/Core/Core/PowerPC/JitInterface.cpp | 7 +- Source/Core/Core/PowerPC/MMU.cpp | 135 +++++++------ Source/Core/Core/PowerPC/MMU.h | 73 ++++--- Source/Core/Core/PowerPC/PPCAnalyst.cpp | 42 ++-- Source/Core/Core/PowerPC/PPCAnalyst.h | 14 +- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 30 +-- Source/Core/Core/PowerPC/PPCSymbolDB.h | 14 +- .../PowerPC/SignatureDB/MEGASignatureDB.cpp | 13 +- .../PowerPC/SignatureDB/MEGASignatureDB.h | 10 +- .../Core/PowerPC/SignatureDB/SignatureDB.cpp | 21 +- .../Core/PowerPC/SignatureDB/SignatureDB.h | 21 +- Source/Core/DiscIO/RiivolutionPatcher.cpp | 51 ++--- Source/Core/DiscIO/RiivolutionPatcher.h | 11 +- Source/Core/DolphinQt/CheatSearchWidget.cpp | 15 +- .../DolphinQt/Debugger/CodeDiffDialog.cpp | 6 +- .../DolphinQt/Debugger/CodeViewWidget.cpp | 175 +++++++++++----- .../Core/DolphinQt/Debugger/CodeViewWidget.h | 6 + Source/Core/DolphinQt/Debugger/CodeWidget.cpp | 76 ++++--- .../DolphinQt/Debugger/MemoryViewWidget.cpp | 90 ++++++--- .../DolphinQt/Debugger/MemoryViewWidget.h | 8 +- .../Core/DolphinQt/Debugger/MemoryWidget.cpp | 27 ++- Source/Core/DolphinQt/Debugger/MemoryWidget.h | 5 + .../DolphinQt/Debugger/RegisterWidget.cpp | 6 +- .../Core/DolphinQt/Debugger/ThreadWidget.cpp | 84 ++++---- Source/Core/DolphinQt/Debugger/ThreadWidget.h | 3 +- .../Core/DolphinQt/Debugger/WatchWidget.cpp | 127 +++++++----- Source/Core/DolphinQt/Debugger/WatchWidget.h | 9 +- Source/Core/DolphinQt/MenuBar.cpp | 77 ++++--- 79 files changed, 1796 insertions(+), 1184 deletions(-) diff --git a/Source/Core/Common/Debug/CodeTrace.cpp b/Source/Core/Common/Debug/CodeTrace.cpp index 65b7826770..3023923fbb 100644 --- a/Source/Core/Common/Debug/CodeTrace.cpp +++ b/Source/Core/Common/Debug/CodeTrace.cpp @@ -122,14 +122,14 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins return tmp_attributes; } -TraceOutput CodeTrace::SaveCurrentInstruction() const +TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard* guard) const { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); // Quickly save instruction and memory target for fast logging. TraceOutput output; - const std::string instr = PowerPC::debug_interface.Disassemble(ppc_state.pc); + const std::string instr = PowerPC::debug_interface.Disassemble(guard, ppc_state.pc); output.instruction = instr; output.address = ppc_state.pc; @@ -139,14 +139,15 @@ TraceOutput CodeTrace::SaveCurrentInstruction() const return output; } -AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on) +AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool continue_previous, + AutoStop stop_on) { AutoStepResults results; - if (!CPU::IsStepping() || m_recording) + if (m_recording) return results; - TraceOutput pc_instr = SaveCurrentInstruction(); + TraceOutput pc_instr = SaveCurrentInstruction(&guard); const InstructionAttributes instr = GetInstructionAttributes(pc_instr); // Not an instruction we should start autostepping from (ie branches). @@ -187,7 +188,6 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on else if (stop_on == AutoStop::Changed) stop_condition = HitType::ACTIVE; - CPU::PauseAndLock(true, false); PowerPC::breakpoints.ClearAllTemporary(); using clock = std::chrono::steady_clock; clock::time_point timeout = clock::now() + std::chrono::seconds(4); @@ -199,7 +199,7 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on { PowerPC::SingleStep(); - pc_instr = SaveCurrentInstruction(); + pc_instr = SaveCurrentInstruction(&guard); hit = TraceLogic(pc_instr); results.count += 1; } while (clock::now() < timeout && hit < stop_condition && @@ -210,7 +210,6 @@ AutoStepResults CodeTrace::AutoStepping(bool continue_previous, AutoStop stop_on results.timed_out = true; PowerPC::SetMode(old_mode); - CPU::PauseAndLock(false, false); m_recording = false; results.reg_tracked = m_reg_autotrack; diff --git a/Source/Core/Common/Debug/CodeTrace.h b/Source/Core/Common/Debug/CodeTrace.h index 4f2cb701f2..15ba67036b 100644 --- a/Source/Core/Common/Debug/CodeTrace.h +++ b/Source/Core/Common/Debug/CodeTrace.h @@ -10,6 +10,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +} + struct InstructionAttributes { u32 address = 0; @@ -63,11 +68,12 @@ public: }; void SetRegTracked(const std::string& reg); - AutoStepResults AutoStepping(bool continue_previous = false, AutoStop stop_on = AutoStop::Always); + AutoStepResults AutoStepping(const Core::CPUThreadGuard& guard, bool continue_previous = false, + AutoStop stop_on = AutoStop::Always); private: InstructionAttributes GetInstructionAttributes(const TraceOutput& line) const; - TraceOutput SaveCurrentInstruction() const; + TraceOutput SaveCurrentInstruction(const Core::CPUThreadGuard* guard) const; HitType TraceLogic(const TraceOutput& current_instr, bool first_hit = false); bool m_recording = false; diff --git a/Source/Core/Common/Debug/MemoryPatches.cpp b/Source/Core/Common/Debug/MemoryPatches.cpp index f48e6e5bb5..d4f7e92379 100644 --- a/Source/Core/Common/Debug/MemoryPatches.cpp +++ b/Source/Core/Common/Debug/MemoryPatches.cpp @@ -23,36 +23,37 @@ MemoryPatch::MemoryPatch(u32 address_, u32 value_) MemoryPatches::MemoryPatches() = default; MemoryPatches::~MemoryPatches() = default; -void MemoryPatches::SetPatch(u32 address, u32 value) +void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { const std::size_t index = m_patches.size(); m_patches.emplace_back(address, value); - Patch(index); + Patch(guard, index); } -void MemoryPatches::SetPatch(u32 address, std::vector value) +void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value) { - UnsetPatch(address); + UnsetPatch(guard, address); const std::size_t index = m_patches.size(); m_patches.emplace_back(address, std::move(value)); - Patch(index); + Patch(guard, index); } -void MemoryPatches::SetFramePatch(u32 address, u32 value) +void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { const std::size_t index = m_patches.size(); m_patches.emplace_back(address, value); m_patches.back().type = MemoryPatch::ApplyType::EachFrame; - Patch(index); + Patch(guard, index); } -void MemoryPatches::SetFramePatch(u32 address, std::vector value) +void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, + std::vector value) { - UnsetPatch(address); + UnsetPatch(guard, address); const std::size_t index = m_patches.size(); m_patches.emplace_back(address, std::move(value)); m_patches.back().type = MemoryPatch::ApplyType::EachFrame; - Patch(index); + Patch(guard, index); } const std::vector& MemoryPatches::GetPatches() const @@ -60,7 +61,7 @@ const std::vector& MemoryPatches::GetPatches() const return m_patches; } -void MemoryPatches::UnsetPatch(u32 address) +void MemoryPatches::UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) { const auto it = std::find_if(m_patches.begin(), m_patches.end(), [address](const auto& patch) { return patch.address == address; }); @@ -69,23 +70,23 @@ void MemoryPatches::UnsetPatch(u32 address) return; const std::size_t index = std::distance(m_patches.begin(), it); - RemovePatch(index); + RemovePatch(guard, index); } -void MemoryPatches::EnablePatch(std::size_t index) +void MemoryPatches::EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { if (m_patches[index].is_enabled == MemoryPatch::State::Enabled) return; m_patches[index].is_enabled = MemoryPatch::State::Enabled; - Patch(index); + Patch(guard, index); } -void MemoryPatches::DisablePatch(std::size_t index) +void MemoryPatches::DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { if (m_patches[index].is_enabled == MemoryPatch::State::Disabled) return; m_patches[index].is_enabled = MemoryPatch::State::Disabled; - Patch(index); + Patch(guard, index); } bool MemoryPatches::HasEnabledPatch(u32 address) const @@ -95,19 +96,19 @@ bool MemoryPatches::HasEnabledPatch(u32 address) const }); } -void MemoryPatches::RemovePatch(std::size_t index) +void MemoryPatches::RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) { - DisablePatch(index); + DisablePatch(guard, index); UnPatch(index); m_patches.erase(m_patches.begin() + index); } -void MemoryPatches::ClearPatches() +void MemoryPatches::ClearPatches(const Core::CPUThreadGuard& guard) { const std::size_t size = m_patches.size(); for (std::size_t index = 0; index < size; ++index) { - DisablePatch(index); + DisablePatch(guard, index); UnPatch(index); } m_patches.clear(); diff --git a/Source/Core/Common/Debug/MemoryPatches.h b/Source/Core/Common/Debug/MemoryPatches.h index 2a4f902dcd..607bb831a0 100644 --- a/Source/Core/Common/Debug/MemoryPatches.h +++ b/Source/Core/Common/Debug/MemoryPatches.h @@ -9,6 +9,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +} + namespace Common::Debug { struct MemoryPatch @@ -40,21 +45,21 @@ public: MemoryPatches(); virtual ~MemoryPatches(); - void SetPatch(u32 address, u32 value); - void SetPatch(u32 address, std::vector value); - void SetFramePatch(u32 address, u32 value); - void SetFramePatch(u32 address, std::vector value); + void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value); + void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value); + void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value); + void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value); const std::vector& GetPatches() const; - void UnsetPatch(u32 address); - void EnablePatch(std::size_t index); - void DisablePatch(std::size_t index); + void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address); + void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index); + void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index); bool HasEnabledPatch(u32 address) const; - void RemovePatch(std::size_t index); - void ClearPatches(); - virtual void ApplyExistingPatch(std::size_t index) = 0; + void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index); + void ClearPatches(const Core::CPUThreadGuard& guard); + virtual void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; protected: - virtual void Patch(std::size_t index) = 0; + virtual void Patch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; virtual void UnPatch(std::size_t index) = 0; std::vector m_patches; diff --git a/Source/Core/Common/Debug/Threads.h b/Source/Core/Common/Debug/Threads.h index 4d6c4354ac..e9aef96d26 100644 --- a/Source/Core/Common/Debug/Threads.h +++ b/Source/Core/Common/Debug/Threads.h @@ -11,6 +11,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +}; + namespace Common::Debug { struct PartialContext @@ -41,7 +46,7 @@ public: LWPThread, // devkitPro libogc thread }; - virtual PartialContext GetContext() const = 0; + virtual PartialContext GetContext(const Core::CPUThreadGuard& guard) const = 0; virtual u32 GetAddress() const = 0; virtual u16 GetState() const = 0; virtual bool IsSuspended() const = 0; @@ -53,8 +58,8 @@ public: virtual std::size_t GetStackSize() const = 0; virtual s32 GetErrno() const = 0; // Implementation specific, used to store arbitrary data - virtual std::string GetSpecific() const = 0; - virtual bool IsValid() const = 0; + virtual std::string GetSpecific(const Core::CPUThreadGuard& guard) const = 0; + virtual bool IsValid(const Core::CPUThreadGuard& guard) const = 0; }; using Threads = std::vector>; diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index 17c10a1894..da6c2dba82 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -16,6 +16,11 @@ struct MemoryPatch; struct Watch; } // namespace Common::Debug +namespace Core +{ +class CPUThreadGuard; +} // namespace Core + namespace Common { class DebugInterface @@ -42,24 +47,29 @@ public: virtual void ClearWatches() = 0; // Memory Patches - virtual void SetPatch(u32 address, u32 value) = 0; - virtual void SetPatch(u32 address, std::vector value) = 0; - virtual void SetFramePatch(u32 address, u32 value) = 0; - virtual void SetFramePatch(u32 address, std::vector value) = 0; + virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0; + virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value) = 0; + virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0; + virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, + std::vector value) = 0; virtual const std::vector& GetPatches() const = 0; - virtual void UnsetPatch(u32 address) = 0; - virtual void EnablePatch(std::size_t index) = 0; - virtual void DisablePatch(std::size_t index) = 0; + virtual void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) = 0; + virtual void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; + virtual void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; virtual bool HasEnabledPatch(u32 address) const = 0; - virtual void RemovePatch(std::size_t index) = 0; - virtual void ClearPatches() = 0; - virtual void ApplyExistingPatch(std::size_t index) = 0; + virtual void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; + virtual void ClearPatches(const Core::CPUThreadGuard& guard) = 0; + virtual void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0; // Threads - virtual Debug::Threads GetThreads() const = 0; + virtual Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const = 0; - virtual std::string Disassemble(u32 /*address*/) const { return "NODEBUGGER"; } - virtual std::string GetRawMemoryString(int /*memory*/, u32 /*address*/) const + virtual std::string Disassemble(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const + { + return "NODEBUGGER"; + } + virtual std::string GetRawMemoryString(const Core::CPUThreadGuard& /*guard*/, int /*memory*/, + u32 /*address*/) const { return "NODEBUGGER"; } @@ -72,10 +82,20 @@ public: virtual void ClearAllMemChecks() {} virtual bool IsMemCheck(u32 /*address*/, size_t /*size*/) const { return false; } virtual void ToggleMemCheck(u32 /*address*/, bool /*read*/, bool /*write*/, bool /*log*/) {} - virtual u32 ReadMemory(u32 /*address*/) const { return 0; } - virtual void WriteExtraMemory(int /*memory*/, u32 /*value*/, u32 /*address*/) {} - virtual u32 ReadExtraMemory(int /*memory*/, u32 /*address*/) const { return 0; } - virtual u32 ReadInstruction(u32 /*address*/) const { return 0; } + virtual u32 ReadMemory(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const { return 0; } + virtual void WriteExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/, + u32 /*value*/, u32 /*address*/) + { + } + virtual u32 ReadExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/, + u32 /*address*/) const + { + return 0; + } + virtual u32 ReadInstruction(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const + { + return 0; + } virtual std::optional GetMemoryAddressFromInstruction(const std::string& /*instruction*/) const { @@ -85,8 +105,11 @@ public: virtual void SetPC(u32 /*address*/) {} virtual void Step() {} virtual void RunToBreakpoint() {} - virtual u32 GetColor(u32 /*address*/) const { return 0xFFFFFFFF; } + virtual u32 GetColor(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const + { + return 0xFFFFFFFF; + } virtual std::string GetDescription(u32 /*address*/) const = 0; - virtual void Clear() = 0; + virtual void Clear(const Core::CPUThreadGuard& guard) = 0; }; } // namespace Common diff --git a/Source/Core/Common/SymbolDB.h b/Source/Core/Common/SymbolDB.h index eef56584ab..c7efa0212a 100644 --- a/Source/Core/Common/SymbolDB.h +++ b/Source/Core/Common/SymbolDB.h @@ -15,6 +15,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +} + namespace Common { struct SCall @@ -68,7 +73,7 @@ public: virtual ~SymbolDB(); virtual Symbol* GetSymbolFromAddr(u32 addr) { return nullptr; } - virtual Symbol* AddFunction(u32 start_addr) { return nullptr; } + virtual Symbol* AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr) { return nullptr; } void AddCompleteSymbol(const Symbol& symbol); Symbol* GetSymbolFromName(std::string_view name); diff --git a/Source/Core/Core/ActionReplay.cpp b/Source/Core/Core/ActionReplay.cpp index c702748003..6d2f1c476e 100644 --- a/Source/Core/Core/ActionReplay.cpp +++ b/Source/Core/Core/ActionReplay.cpp @@ -358,7 +358,8 @@ bool IsSelfLogging() // ---------------------- // Code Functions -static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) +static bool Subtype_RamWriteAndFill(const Core::CPUThreadGuard& guard, const ARAddr& addr, + const u32 data) { const u32 new_addr = addr.GCAddress(); @@ -374,7 +375,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) const u32 repeat = data >> 8; for (u32 i = 0; i <= repeat; ++i) { - PowerPC::HostWrite_U8(data & 0xFF, new_addr + i); + PowerPC::HostWrite_U8(guard, data & 0xFF, new_addr + i); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFF, new_addr + i); } LogInfo("--------"); @@ -388,7 +389,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) const u32 repeat = data >> 16; for (u32 i = 0; i <= repeat; ++i) { - PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2); + PowerPC::HostWrite_U16(guard, data & 0xFFFF, new_addr + i * 2); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFFFF, new_addr + i * 2); } LogInfo("--------"); @@ -399,7 +400,7 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) case DATATYPE_32BIT: // Dword write LogInfo("32-bit Write"); LogInfo("--------"); - PowerPC::HostWrite_U32(data, new_addr); + PowerPC::HostWrite_U32(guard, data, new_addr); LogInfo("Wrote {:08x} to address {:08x}", data, new_addr); LogInfo("--------"); break; @@ -415,10 +416,11 @@ static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) return true; } -static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) +static bool Subtype_WriteToPointer(const Core::CPUThreadGuard& guard, const ARAddr& addr, + const u32 data) { const u32 new_addr = addr.GCAddress(); - const u32 ptr = PowerPC::HostRead_U32(new_addr); + const u32 ptr = PowerPC::HostRead_U32(guard, new_addr); LogInfo("Hardware Address: {:08x}", new_addr); LogInfo("Size: {:08x}", addr.size); @@ -434,7 +436,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) LogInfo("Pointer: {:08x}", ptr); LogInfo("Byte: {:08x}", thebyte); LogInfo("Offset: {:08x}", offset); - PowerPC::HostWrite_U8(thebyte, ptr + offset); + PowerPC::HostWrite_U8(guard, thebyte, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", thebyte, ptr + offset); LogInfo("--------"); break; @@ -449,7 +451,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) LogInfo("Pointer: {:08x}", ptr); LogInfo("Byte: {:08x}", theshort); LogInfo("Offset: {:08x}", offset); - PowerPC::HostWrite_U16(theshort, ptr + offset); + PowerPC::HostWrite_U16(guard, theshort, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", theshort, ptr + offset); LogInfo("--------"); break; @@ -459,7 +461,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) case DATATYPE_32BIT: LogInfo("Write 32-bit to pointer"); LogInfo("--------"); - PowerPC::HostWrite_U32(data, ptr); + PowerPC::HostWrite_U32(guard, data, ptr); LogInfo("Wrote {:08x} to address {:08x}", data, ptr); LogInfo("--------"); break; @@ -474,7 +476,7 @@ static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) return true; } -static bool Subtype_AddCode(const ARAddr& addr, const u32 data) +static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data) { // Used to increment/decrement a value in memory const u32 new_addr = addr.GCAddress(); @@ -487,24 +489,24 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data) case DATATYPE_8BIT: LogInfo("8-bit Add"); LogInfo("--------"); - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr); - LogInfo("Wrote {:02x} to address {:08x}", PowerPC::HostRead_U8(new_addr), new_addr); + PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, new_addr) + data, new_addr); + LogInfo("Wrote {:02x} to address {:08x}", PowerPC::HostRead_U8(guard, new_addr), new_addr); LogInfo("--------"); break; case DATATYPE_16BIT: LogInfo("16-bit Add"); LogInfo("--------"); - PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr); - LogInfo("Wrote {:04x} to address {:08x}", PowerPC::HostRead_U16(new_addr), new_addr); + PowerPC::HostWrite_U16(guard, PowerPC::HostRead_U16(guard, new_addr) + data, new_addr); + LogInfo("Wrote {:04x} to address {:08x}", PowerPC::HostRead_U16(guard, new_addr), new_addr); LogInfo("--------"); break; case DATATYPE_32BIT: LogInfo("32-bit Add"); LogInfo("--------"); - PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr); - LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U32(new_addr), new_addr); + PowerPC::HostWrite_U32(guard, PowerPC::HostRead_U32(guard, new_addr) + data, new_addr); + LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U32(guard, new_addr), new_addr); LogInfo("--------"); break; @@ -513,12 +515,12 @@ static bool Subtype_AddCode(const ARAddr& addr, const u32 data) LogInfo("32-bit floating Add"); LogInfo("--------"); - const u32 read = PowerPC::HostRead_U32(new_addr); + const u32 read = PowerPC::HostRead_U32(guard, new_addr); const float read_float = Common::BitCast(read); // data contains an (unsigned?) integer value const float fread = read_float + static_cast(data); const u32 newval = Common::BitCast(fread); - PowerPC::HostWrite_U32(newval, new_addr); + PowerPC::HostWrite_U32(guard, newval, new_addr); LogInfo("Old Value {:08x}", read); LogInfo("Increment {:08x}", data); LogInfo("New value {:08x}", newval); @@ -550,7 +552,8 @@ static bool Subtype_MasterCodeAndWriteToCCXXXXXX(const ARAddr& addr, const u32 d } // This needs more testing -static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const u32 data) +static bool ZeroCode_FillAndSlide(const Core::CPUThreadGuard& guard, const u32 val_last, + const ARAddr& addr, const u32 data) { const u32 new_addr = ARAddr(val_last).GCAddress(); const u8 size = ARAddr(val_last).size; @@ -575,7 +578,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const LogInfo("--------"); for (int i = 0; i < write_num; ++i) { - PowerPC::HostWrite_U8(val & 0xFF, curr_addr); + PowerPC::HostWrite_U8(guard, val & 0xFF, curr_addr); curr_addr += addr_incr; val += val_incr; LogInfo("Write {:08x} to address {:08x}", val & 0xFF, curr_addr); @@ -591,7 +594,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const LogInfo("--------"); for (int i = 0; i < write_num; ++i) { - PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr); + PowerPC::HostWrite_U16(guard, val & 0xFFFF, curr_addr); LogInfo("Write {:08x} to address {:08x}", val & 0xFFFF, curr_addr); curr_addr += addr_incr * 2; val += val_incr; @@ -606,7 +609,7 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const LogInfo("--------"); for (int i = 0; i < write_num; ++i) { - PowerPC::HostWrite_U32(val, curr_addr); + PowerPC::HostWrite_U32(guard, val, curr_addr); LogInfo("Write {:08x} to address {:08x}", val, curr_addr); curr_addr += addr_incr * 4; val += val_incr; @@ -629,7 +632,8 @@ static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const // kenobi's "memory copy" Z-code. Requires an additional master code // on a real AR device. Documented here: // https://github.com/dolphin-emu/dolphin/wiki/GameCube-Action-Replay-Code-Types#type-z4-size-3--memory-copy -static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u32 data) +static bool ZeroCode_MemoryCopy(const Core::CPUThreadGuard& guard, const u32 val_last, + const ARAddr& addr, const u32 data) { const u32 addr_dest = val_last & ~0x06000000; const u32 addr_src = addr.GCAddress(); @@ -646,14 +650,15 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3 { // Memory Copy With Pointers Support LogInfo("Memory Copy With Pointers Support"); LogInfo("--------"); - const u32 ptr_dest = PowerPC::HostRead_U32(addr_dest); + const u32 ptr_dest = PowerPC::HostRead_U32(guard, addr_dest); LogInfo("Resolved Dest Address to: {:08x}", ptr_dest); - const u32 ptr_src = PowerPC::HostRead_U32(addr_src); + const u32 ptr_src = PowerPC::HostRead_U32(guard, addr_src); LogInfo("Resolved Src Address to: {:08x}", ptr_src); for (int i = 0; i < num_bytes; ++i) { - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(ptr_src + i), ptr_dest + i); - LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(ptr_src + i), ptr_dest + i); + PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, ptr_src + i), ptr_dest + i); + LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(guard, ptr_src + i), + ptr_dest + i); } LogInfo("--------"); } @@ -663,8 +668,8 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3 LogInfo("--------"); for (int i = 0; i < num_bytes; ++i) { - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); - LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(addr_src + i), + PowerPC::HostWrite_U8(guard, PowerPC::HostRead_U8(guard, addr_src + i), addr_dest + i); + LogInfo("Wrote {:08x} to address {:08x}", PowerPC::HostRead_U8(guard, addr_src + i), addr_dest + i); } LogInfo("--------"); @@ -681,25 +686,25 @@ static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u3 return true; } -static bool NormalCode(const ARAddr& addr, const u32 data) +static bool NormalCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data) { switch (addr.subtype) { case SUB_RAM_WRITE: // Ram write (and fill) LogInfo("Doing Ram Write And Fill"); - if (!Subtype_RamWriteAndFill(addr, data)) + if (!Subtype_RamWriteAndFill(guard, addr, data)) return false; break; case SUB_WRITE_POINTER: // Write to pointer LogInfo("Doing Write To Pointer"); - if (!Subtype_WriteToPointer(addr, data)) + if (!Subtype_WriteToPointer(guard, addr, data)) return false; break; case SUB_ADD_CODE: // Increment Value LogInfo("Doing Add Code"); - if (!Subtype_AddCode(addr, data)) + if (!Subtype_AddCode(guard, addr, data)) return false; break; @@ -759,7 +764,8 @@ static bool CompareValues(const u32 val1, const u32 val2, const int type) } } -static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkipCount) +static bool ConditionalCode(const Core::CPUThreadGuard& guard, const ARAddr& addr, const u32 data, + int* const pSkipCount) { const u32 new_addr = addr.GCAddress(); @@ -771,16 +777,16 @@ static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkip switch (addr.size) { case DATATYPE_8BIT: - result = CompareValues(PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type); + result = CompareValues(PowerPC::HostRead_U8(guard, new_addr), (data & 0xFF), addr.type); break; case DATATYPE_16BIT: - result = CompareValues(PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type); + result = CompareValues(PowerPC::HostRead_U16(guard, new_addr), (data & 0xFFFF), addr.type); break; case DATATYPE_32BIT_FLOAT: case DATATYPE_32BIT: - result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type); + result = CompareValues(PowerPC::HostRead_U32(guard, new_addr), data, addr.type); break; default: @@ -819,7 +825,7 @@ static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkip } // NOTE: Lock needed to give mutual exclusion to s_current_code and LogInfo -static bool RunCodeLocked(const ARCode& arcode) +static bool RunCodeLocked(const Core::CPUThreadGuard& guard, const ARCode& arcode) { // The mechanism is different than what the real AR uses, so there may be compatibility problems. @@ -873,7 +879,7 @@ static bool RunCodeLocked(const ARCode& arcode) { do_fill_and_slide = false; LogInfo("Doing Fill And Slide"); - if (false == ZeroCode_FillAndSlide(val_last, addr, data)) + if (false == ZeroCode_FillAndSlide(guard, val_last, addr, data)) return false; continue; } @@ -883,7 +889,7 @@ static bool RunCodeLocked(const ARCode& arcode) { do_memory_copy = false; LogInfo("Doing Memory Copy"); - if (false == ZeroCode_MemoryCopy(val_last, addr, data)) + if (false == ZeroCode_MemoryCopy(guard, val_last, addr, data)) return false; continue; } @@ -962,13 +968,13 @@ static bool RunCodeLocked(const ARCode& arcode) switch (addr.type) { case 0x00: - if (false == NormalCode(addr, data)) + if (false == NormalCode(guard, addr, data)) return false; break; default: LogInfo("This Normal Code is a Conditional Code"); - if (false == ConditionalCode(addr, data, &skip_count)) + if (false == ConditionalCode(guard, addr, data, &skip_count)) return false; break; } @@ -977,7 +983,7 @@ static bool RunCodeLocked(const ARCode& arcode) return true; } -void RunAllActive() +void RunAllActive(const Core::CPUThreadGuard& cpu_guard) { if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) return; @@ -987,8 +993,8 @@ void RunAllActive() // be contested. std::lock_guard guard(s_lock); s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(), - [](const ARCode& code) { - bool success = RunCodeLocked(code); + [&cpu_guard](const ARCode& code) { + bool success = RunCodeLocked(cpu_guard, code); LogInfo("\n"); return !success; }), diff --git a/Source/Core/Core/ActionReplay.h b/Source/Core/Core/ActionReplay.h index 1c7fb61fa9..4681bb887c 100644 --- a/Source/Core/Core/ActionReplay.h +++ b/Source/Core/Core/ActionReplay.h @@ -12,6 +12,11 @@ class IniFile; +namespace Core +{ +class CPUThreadGuard; +}; + namespace ActionReplay { struct AREntry @@ -35,7 +40,7 @@ struct ARCode bool user_defined = false; }; -void RunAllActive(); +void RunAllActive(const Core::CPUThreadGuard& cpu_guard); void ApplyCodes(std::span codes); void SetSyncedCodesAsActive(); diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 9362b9ef29..09877c5a80 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -375,11 +375,11 @@ bool CBoot::FindMapFile(std::string* existing_map_file, std::string* writable_ma return false; } -bool CBoot::LoadMapFromFilename() +bool CBoot::LoadMapFromFilename(const Core::CPUThreadGuard& guard) { std::string strMapFilename; bool found = FindMapFile(&strMapFilename, nullptr); - if (found && g_symbolDB.LoadMap(strMapFilename)) + if (found && g_symbolDB.LoadMap(guard, strMapFilename)) { UpdateDebugger_MapLoaded(); return true; @@ -486,7 +486,8 @@ static void CopyDefaultExceptionHandlers(Core::System& system) } // Third boot step after BootManager and Core. See Call schedule in BootManager.cpp -bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) +bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, + std::unique_ptr boot) { SConfig& config = SConfig::GetInstance(); @@ -502,8 +503,10 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) struct BootTitle { - BootTitle(Core::System& system_, const std::vector& patches) - : system(system_), config(SConfig::GetInstance()), riivolution_patches(patches) + BootTitle(Core::System& system_, const Core::CPUThreadGuard& guard_, + const std::vector& patches) + : system(system_), guard(guard_), config(SConfig::GetInstance()), + riivolution_patches(patches) { } bool operator()(BootParameters::Disc& disc) const @@ -515,10 +518,10 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) if (!volume) return false; - if (!EmulatedBS2(system, config.bWii, *volume, riivolution_patches)) + if (!EmulatedBS2(system, guard, config.bWii, *volume, riivolution_patches)) return false; - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); return true; } @@ -551,7 +554,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) } else { - SetupGCMemory(system); + SetupGCMemory(system, guard); } if (!executable.reader->LoadIntoMemory()) @@ -560,11 +563,11 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) return false; } - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); ppc_state.pc = executable.reader->GetEntryPoint(); - if (executable.reader->LoadSymbols()) + if (executable.reader->LoadSymbols(guard)) { UpdateDebugger_MapLoaded(); HLE::PatchFunctions(system); @@ -578,7 +581,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) if (!Boot_WiiWAD(system, wad)) return false; - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); return true; } @@ -588,7 +591,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) if (!BootNANDTitle(system, nand_title.id)) return false; - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); return true; } @@ -613,7 +616,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) SetDisc(DiscIO::CreateDisc(ipl.disc->path), ipl.disc->auto_disc_change_paths); } - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); return true; } @@ -625,14 +628,15 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) private: Core::System& system; + const Core::CPUThreadGuard& guard; const SConfig& config; const std::vector& riivolution_patches; }; - if (!std::visit(BootTitle(system, boot->riivolution_patches), boot->parameters)) + if (!std::visit(BootTitle(system, guard, boot->riivolution_patches), boot->parameters)) return false; - DiscIO::Riivolution::ApplyGeneralMemoryPatches(boot->riivolution_patches); + DiscIO::Riivolution::ApplyGeneralMemoryPatches(guard, boot->riivolution_patches); return true; } diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 78edad92cd..47eab60add 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -21,8 +21,9 @@ namespace Core { +class CPUThreadGuard; class System; -} +} // namespace Core namespace File { @@ -153,7 +154,8 @@ struct BootParameters class CBoot { public: - static bool BootUp(Core::System& system, std::unique_ptr boot); + static bool BootUp(Core::System& system, const Core::CPUThreadGuard& guard, + std::unique_ptr boot); // Tries to find a map file for the current game by looking first in the // local user directory, then in the shared user directory. @@ -166,7 +168,7 @@ public: // // Returns true if a map file exists, false if none could be found. static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file); - static bool LoadMapFromFilename(); + static bool LoadMapFromFilename(const Core::CPUThreadGuard& guard); private: static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address, @@ -182,17 +184,21 @@ private: static void SetupMSR(PowerPC::PowerPCState& ppc_state); static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii); static void SetupBAT(Core::System& system, bool is_wii); - static bool RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, + static bool RunApploader(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches); - static bool EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume, + static bool EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& guard, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches); - static bool EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volume, + static bool EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& guard, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches); - static bool EmulatedBS2(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, + static bool EmulatedBS2(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches); static bool Load_BS2(Core::System& system, const std::string& boot_rom_filename); - static void SetupGCMemory(Core::System& system); + static void SetupGCMemory(Core::System& system, const Core::CPUThreadGuard& guard); static bool SetupWiiMemory(Core::System& system, IOS::HLE::IOSC::ConsoleType console_type); }; @@ -208,7 +214,7 @@ public: virtual bool IsValid() const = 0; virtual bool IsWii() const = 0; virtual bool LoadIntoMemory(bool only_in_mem1 = false) const = 0; - virtual bool LoadSymbols() const = 0; + virtual bool LoadSymbols(const Core::CPUThreadGuard& guard) const = 0; protected: std::vector m_bytes; diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index f42093f4e5..df6acd0976 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -44,14 +44,14 @@ namespace { -void PresetTimeBaseTicks() +void PresetTimeBaseTicks(const Core::CPUThreadGuard& guard) { const u64 emulated_time = ExpansionInterface::CEXIIPL::GetEmulatedTime(ExpansionInterface::CEXIIPL::GC_EPOCH); const u64 time_base_ticks = emulated_time * 40500000ULL; - PowerPC::HostWrite_U64(time_base_ticks, 0x800030D8); + PowerPC::HostWrite_U64(guard, time_base_ticks, 0x800030D8); } } // Anonymous namespace @@ -131,7 +131,8 @@ void CBoot::SetupBAT(Core::System& system, bool is_wii) PowerPC::IBATUpdated(); } -bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, +bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches) { const DiscIO::Partition partition = volume.GetGamePartition(); @@ -166,8 +167,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume // iAppLoaderInit DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit"); - PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR - HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader + PowerPC::HostWrite_U32(guard, 0x4E800020, 0x81300000); // Write BLR + HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader ppc_state.gpr[3] = 0x81300000; RunFunction(system, iAppLoaderInit); @@ -196,7 +197,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume ram_address, length); DVDRead(volume, dvd_offset, ram_address, length, partition); - DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length); + DiscIO::Riivolution::ApplyApploaderMemoryPatches(guard, riivolution_patches, ram_address, + length); ppc_state.gpr[3] = 0x81300004; ppc_state.gpr[4] = 0x81300008; @@ -216,36 +218,37 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume return true; } -void CBoot::SetupGCMemory(Core::System& system) +void CBoot::SetupGCMemory(Core::System& system, const Core::CPUThreadGuard& guard) { auto& memory = system.GetMemory(); // Booted from bootrom. 0xE5207C22 = booted from jtag - PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); + PowerPC::HostWrite_U32(guard, 0x0D15EA5E, 0x80000020); // Physical Memory Size (24MB on retail) - PowerPC::HostWrite_U32(memory.GetRamSizeReal(), 0x80000028); + PowerPC::HostWrite_U32(guard, memory.GetRamSizeReal(), 0x80000028); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2 // TODO: determine why some games fail when using a retail ID. // (Seem to take different EXI paths, see Ikaruga for example) const u32 console_type = static_cast(Core::ConsoleType::LatestDevkit); - PowerPC::HostWrite_U32(console_type, 0x8000002C); + PowerPC::HostWrite_U32(guard, console_type, 0x8000002C); // Fake the VI Init of the IPL (YAGCD 4.2.1.4) - PowerPC::HostWrite_U32(DiscIO::IsNTSC(SConfig::GetInstance().m_region) ? 0 : 1, 0x800000CC); + PowerPC::HostWrite_U32(guard, DiscIO::IsNTSC(SConfig::GetInstance().m_region) ? 0 : 1, + 0x800000CC); - PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external - // (retail consoles have no external ARAM) + // ARAM Size. 16MB main + 4/16/32MB external. (retail consoles have no external ARAM) + PowerPC::HostWrite_U32(guard, 0x01000000, 0x800000d0); - PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed - PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed + PowerPC::HostWrite_U32(guard, 0x09a7ec80, 0x800000F8); // Bus Clock Speed + PowerPC::HostWrite_U32(guard, 0x1cf7c580, 0x800000FC); // CPU Clock Speed - PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DSI Handler: rfi - PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi - PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi + PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000300); // Write default DSI Handler: rfi + PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000800); // Write default FPU Handler: rfi + PowerPC::HostWrite_U32(guard, 0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi - PresetTimeBaseTicks(); + PresetTimeBaseTicks(guard); // HIO checks this // PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type @@ -255,7 +258,8 @@ void CBoot::SetupGCMemory(Core::System& system) // GameCube Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader, function by function, using the above utility. -bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volume, +bool CBoot::EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& guard, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches) { INFO_LOG_FMT(BOOT, "Faking GC BS2..."); @@ -266,7 +270,7 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum SetupHID(ppc_state, /*is_wii*/ false); SetupBAT(system, /*is_wii*/ false); - SetupGCMemory(system); + SetupGCMemory(system, guard); // Datel titles don't initialize the postMatrices, but they have dual-texture coordinate // transformation enabled. We initialize all of xfmem to 0, which results in everything using @@ -309,7 +313,7 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const DiscIO::VolumeDisc& volum // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) ppc_state.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0; - return RunApploader(system, /*is_wii*/ false, volume, riivolution_patches); + return RunApploader(system, guard, /*is_wii*/ false, volume, riivolution_patches); } static DiscIO::Region CodeRegion(char c) @@ -507,7 +511,8 @@ static void WriteEmptyPlayRecord() // Wii Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader -bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volume, +bool CBoot::EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& guard, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches) { INFO_LOG_FMT(BOOT, "Faking Wii BS2..."); @@ -578,7 +583,7 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu ppc_state.gpr[1] = 0x816ffff0; // StackPointer - if (!RunApploader(system, /*is_wii*/ true, volume, riivolution_patches)) + if (!RunApploader(system, guard, /*is_wii*/ true, volume, riivolution_patches)) return false; // The Apploader probably just overwrote values needed for RAM Override. Run this again! @@ -593,9 +598,10 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const DiscIO::VolumeDisc& volu // Returns true if apploader has run successfully. If is_wii is true, the disc // that volume refers to must currently be inserted into the emulated disc drive. -bool CBoot::EmulatedBS2(Core::System& system, bool is_wii, const DiscIO::VolumeDisc& volume, +bool CBoot::EmulatedBS2(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii, + const DiscIO::VolumeDisc& volume, const std::vector& riivolution_patches) { - return is_wii ? EmulatedBS2_Wii(system, volume, riivolution_patches) : - EmulatedBS2_GC(system, volume, riivolution_patches); + return is_wii ? EmulatedBS2_Wii(system, guard, volume, riivolution_patches) : + EmulatedBS2_GC(system, guard, volume, riivolution_patches); } diff --git a/Source/Core/Core/Boot/DolReader.h b/Source/Core/Core/Boot/DolReader.h index 5025b1c82d..4ceef9bd8b 100644 --- a/Source/Core/Core/Boot/DolReader.h +++ b/Source/Core/Core/Boot/DolReader.h @@ -27,7 +27,7 @@ public: bool IsAncast() const { return m_is_ancast; }; u32 GetEntryPoint() const override { return m_dolheader.entryPoint; } bool LoadIntoMemory(bool only_in_mem1 = false) const override; - bool LoadSymbols() const override { return false; } + bool LoadSymbols(const Core::CPUThreadGuard& guard) const override { return false; } private: enum diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index 14a774039e..85024857e3 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -181,7 +181,7 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const return -1; } -bool ElfReader::LoadSymbols() const +bool ElfReader::LoadSymbols(const Core::CPUThreadGuard& guard) const { bool hasSymbols = false; SectionID sec = GetSectionByName(".symtab"); @@ -219,7 +219,7 @@ bool ElfReader::LoadSymbols() const default: continue; } - g_symbolDB.AddKnownSymbol(value, size, name, symtype); + g_symbolDB.AddKnownSymbol(guard, value, size, name, symtype); hasSymbols = true; } } diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 3c4ffc7756..8c5406776d 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -36,7 +36,7 @@ public: u32 GetEntryPoint() const override { return entryPoint; } u32 GetFlags() const { return (u32)(header->e_flags); } bool LoadIntoMemory(bool only_in_mem1 = false) const override; - bool LoadSymbols() const override; + bool LoadSymbols(const Core::CPUThreadGuard& guard) const override; // TODO: actually check for validity. bool IsValid() const override { return true; } bool IsWii() const override; diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index e03fa8d0b3..101d44726f 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -103,41 +103,47 @@ namespace { template static std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space); +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space); template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadU8(addr, space); + return PowerPC::HostTryReadU8(guard, addr, space); } template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadU16(addr, space); + return PowerPC::HostTryReadU16(guard, addr, space); } template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadU32(addr, space); + return PowerPC::HostTryReadU32(guard, addr, space); } template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadU64(addr, space); + return PowerPC::HostTryReadU64(guard, addr, space); } template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - auto tmp = PowerPC::HostTryReadU8(addr, space); + auto tmp = PowerPC::HostTryReadU8(guard, addr, space); if (!tmp) return std::nullopt; return PowerPC::ReadResult(tmp->translated, Common::BitCast(tmp->value)); @@ -145,9 +151,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - auto tmp = PowerPC::HostTryReadU16(addr, space); + auto tmp = PowerPC::HostTryReadU16(guard, addr, space); if (!tmp) return std::nullopt; return PowerPC::ReadResult(tmp->translated, Common::BitCast(tmp->value)); @@ -155,9 +162,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - auto tmp = PowerPC::HostTryReadU32(addr, space); + auto tmp = PowerPC::HostTryReadU32(guard, addr, space); if (!tmp) return std::nullopt; return PowerPC::ReadResult(tmp->translated, Common::BitCast(tmp->value)); @@ -165,9 +173,10 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - auto tmp = PowerPC::HostTryReadU64(addr, space); + auto tmp = PowerPC::HostTryReadU64(guard, addr, space); if (!tmp) return std::nullopt; return PowerPC::ReadResult(tmp->translated, Common::BitCast(tmp->value)); @@ -175,22 +184,25 @@ TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadF32(addr, space); + return PowerPC::HostTryReadF32(guard, addr, space); } template <> std::optional> -TryReadValueFromEmulatedMemory(u32 addr, PowerPC::RequestedAddressSpace space) +TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, + PowerPC::RequestedAddressSpace space) { - return PowerPC::HostTryReadF64(addr, space); + return PowerPC::HostTryReadF64(guard, addr, space); } } // namespace template Common::Result>> -Cheats::NewSearch(const std::vector& memory_ranges, +Cheats::NewSearch(const Core::CPUThreadGuard& guard, + const std::vector& memory_ranges, PowerPC::RequestedAddressSpace address_space, bool aligned, const std::function& validator) { @@ -229,7 +241,7 @@ Cheats::NewSearch(const std::vector& memory_ranges, for (u64 i = 0; i < length; i += increment_per_loop) { const u32 addr = start_address + i; - const auto current_value = TryReadValueFromEmulatedMemory(addr, address_space); + const auto current_value = TryReadValueFromEmulatedMemory(guard, addr, address_space); if (!current_value) continue; @@ -252,7 +264,8 @@ Cheats::NewSearch(const std::vector& memory_ranges, template Common::Result>> -Cheats::NextSearch(const std::vector>& previous_results, +Cheats::NextSearch(const Core::CPUThreadGuard& guard, + const std::vector>& previous_results, PowerPC::RequestedAddressSpace address_space, const std::function& validator) { @@ -277,7 +290,7 @@ Cheats::NextSearch(const std::vector>& previous_results, for (const auto& previous_result : previous_results) { const u32 addr = previous_result.m_address; - const auto current_value = TryReadValueFromEmulatedMemory(addr, address_space); + const auto current_value = TryReadValueFromEmulatedMemory(guard, addr, address_space); if (!current_value) { auto& r = results.emplace_back(); @@ -429,7 +442,7 @@ MakeCompareFunctionForLastValue(Cheats::CompareType op) } template -Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch() +Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch(const Core::CPUThreadGuard& guard) { Common::Result>> result = Cheats::SearchErrorCode::InvalidParameters; @@ -442,12 +455,12 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch() if (m_first_search_done) { result = Cheats::NextSearch( - m_search_results, m_address_space, + guard, m_search_results, m_address_space, [&func](const T& new_value, const T& old_value) { return func(new_value); }); } else { - result = Cheats::NewSearch(m_memory_ranges, m_address_space, m_aligned, func); + result = Cheats::NewSearch(guard, m_memory_ranges, m_address_space, m_aligned, func); } } else if (m_filter_type == FilterType::CompareAgainstLastValue) @@ -455,19 +468,19 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch() if (!m_first_search_done) return Cheats::SearchErrorCode::InvalidParameters; - result = Cheats::NextSearch(m_search_results, m_address_space, + result = Cheats::NextSearch(guard, m_search_results, m_address_space, MakeCompareFunctionForLastValue(m_compare_type)); } else if (m_filter_type == FilterType::DoNotFilter) { if (m_first_search_done) { - result = Cheats::NextSearch(m_search_results, m_address_space, + result = Cheats::NextSearch(guard, m_search_results, m_address_space, [](const T& v1, const T& v2) { return true; }); } else { - result = Cheats::NewSearch(m_memory_ranges, m_address_space, m_aligned, + result = Cheats::NewSearch(guard, m_memory_ranges, m_address_space, m_aligned, [](const T& v) { return true; }); } } diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index 8876d2ad86..696347fcf3 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -14,6 +14,11 @@ #include "Common/Result.h" #include "Core/PowerPC/MMU.h" +namespace Core +{ +class CPUThreadGuard; +}; + namespace Cheats { enum class CompareType @@ -108,7 +113,7 @@ std::vector GetValueAsByteVector(const SearchValue& value); // for which the given validator returns true. template Common::Result>> -NewSearch(const std::vector& memory_ranges, +NewSearch(const Core::CPUThreadGuard& guard, const std::vector& memory_ranges, PowerPC::RequestedAddressSpace address_space, bool aligned, const std::function& validator); @@ -116,7 +121,7 @@ NewSearch(const std::vector& memory_ranges, // which the given validator returns true. template Common::Result>> -NextSearch(const std::vector>& previous_results, +NextSearch(const Core::CPUThreadGuard& guard, const std::vector>& previous_results, PowerPC::RequestedAddressSpace address_space, const std::function& validator); @@ -138,7 +143,7 @@ public: virtual void ResetResults() = 0; // Run either a new search or a next search based on the current state of this session. - virtual SearchErrorCode RunSearch() = 0; + virtual SearchErrorCode RunSearch(const Core::CPUThreadGuard& guard) = 0; virtual size_t GetMemoryRangeCount() const = 0; virtual MemoryRange GetMemoryRange(size_t index) const = 0; @@ -184,7 +189,7 @@ public: bool SetValueFromString(const std::string& value_as_string, bool force_parse_as_hex) override; void ResetResults() override; - SearchErrorCode RunSearch() override; + SearchErrorCode RunSearch(const Core::CPUThreadGuard& guard) override; size_t GetMemoryRangeCount() const override; MemoryRange GetMemoryRange(size_t index) const override; diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 5f264d2bbf..2b4f5be5b3 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -191,7 +191,7 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri DolphinAnalytics::Instance().ReportGameStart(); } -void SConfig::OnNewTitleLoad() +void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard& guard) { if (!Core::IsRunning()) return; @@ -201,7 +201,7 @@ void SConfig::OnNewTitleLoad() g_symbolDB.Clear(); Host_NotifyMapLoaded(); } - CBoot::LoadMapFromFilename(); + CBoot::LoadMapFromFilename(guard); auto& system = Core::System::GetInstance(); HLE::Reload(system); PatchEngine::Reload(); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 6a6045c0f8..5f3f325983 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -16,6 +16,11 @@ class IniFile; +namespace Core +{ +class CPUThreadGuard; +} + namespace DiscIO { enum class Language; @@ -68,7 +73,7 @@ struct SConfig void SetRunningGameMetadata(const std::string& game_id); // Reloads title-specific map files, patches, custom textures, etc. // This should only be called after the new title has been loaded into memory. - static void OnNewTitleLoad(); + static void OnNewTitleLoad(const Core::CPUThreadGuard& guard); void LoadDefaults(); static std::string MakeGameID(std::string_view file_name); diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 1f627705e9..3bc9457003 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -166,7 +166,12 @@ void OnFrameEnd() { #ifdef USE_MEMORYWATCHER if (s_memory_watcher) - s_memory_watcher->Step(); + { + ASSERT(IsCPUThread()); + CPUThreadGuard guard; + + s_memory_watcher->Step(guard); + } #endif } @@ -537,7 +542,9 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi PatchEngine::Shutdown(); HLE::Clear(); - PowerPC::debug_interface.Clear(); + + CPUThreadGuard guard; + PowerPC::debug_interface.Clear(guard); }}; VideoBackendBase::PopulateBackendInfo(); @@ -587,8 +594,12 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi if (SConfig::GetInstance().bWii) savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches); - if (!CBoot::BootUp(system, std::move(boot))) - return; + { + ASSERT(IsCPUThread()); + CPUThreadGuard guard; + if (!CBoot::BootUp(system, guard, std::move(boot))) + return; + } // Initialise Wii filesystem contents. // This is done here after Boot and not in BootManager to ensure that we operate @@ -1036,4 +1047,16 @@ void UpdateInputGate(bool require_focus, bool require_full_focus) ControlReference::SetInputGate(focus_passes && full_focus_passes); } +CPUThreadGuard::CPUThreadGuard() : m_was_cpu_thread(IsCPUThread()) +{ + if (!m_was_cpu_thread) + m_was_unpaused = PauseAndLock(true, true); +} + +CPUThreadGuard::~CPUThreadGuard() +{ + if (!m_was_cpu_thread) + PauseAndLock(false, m_was_unpaused); +} + } // namespace Core diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 9c01145e39..26abd24d97 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -92,6 +92,33 @@ enum class ConsoleType : u32 ReservedTDEVSystem = 0x20000007, }; +// Run a function as the CPU thread. This is an RAII alternative to the RunAsCPUThread function. +// +// If constructed from the Host thread, the CPU thread is paused and the current thread temporarily +// becomes the CPU thread. +// If constructed from the CPU thread, nothing special happens. +// +// This should only be constructed from the CPU thread or the host thread. +// +// Some functions use a parameter of this type to indicate that the function should only be called +// from the CPU thread. If the parameter is a pointer, the function has a fallback for being called +// from the wrong thread (with the argument being set to nullptr). +class CPUThreadGuard final +{ +public: + CPUThreadGuard(); + ~CPUThreadGuard(); + + CPUThreadGuard(const CPUThreadGuard&) = delete; + CPUThreadGuard(CPUThreadGuard&&) = delete; + CPUThreadGuard& operator=(const CPUThreadGuard&) = delete; + CPUThreadGuard& operator=(CPUThreadGuard&&) = delete; + +private: + const bool m_was_cpu_thread; + bool m_was_unpaused = false; +}; + bool Init(std::unique_ptr boot, const WindowSystemInfo& wsi); void Stop(); void Shutdown(); diff --git a/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp b/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp index 4909103976..023c004897 100644 --- a/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp +++ b/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp @@ -39,29 +39,30 @@ void AddAutoBreakpoints() } // Returns true if the address is not a valid RAM address or NULL. -static bool IsStackBottom(u32 addr) +static bool IsStackBottom(const Core::CPUThreadGuard& guard, u32 addr) { - return !addr || !PowerPC::HostIsRAMAddress(addr); + return !addr || !PowerPC::HostIsRAMAddress(guard, addr); } -static void WalkTheStack(Core::System& system, const std::function& stack_step) +static void WalkTheStack(Core::System& system, const Core::CPUThreadGuard& guard, + const std::function& stack_step) { auto& ppc_state = system.GetPPCState(); - if (!IsStackBottom(ppc_state.gpr[1])) + if (!IsStackBottom(guard, ppc_state.gpr[1])) { - u32 addr = PowerPC::HostRead_U32(ppc_state.gpr[1]); // SP + u32 addr = PowerPC::HostRead_U32(guard, ppc_state.gpr[1]); // SP // Walk the stack chain - for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count) + for (int count = 0; !IsStackBottom(guard, addr + 4) && (count++ < 20); ++count) { - u32 func_addr = PowerPC::HostRead_U32(addr + 4); + u32 func_addr = PowerPC::HostRead_U32(guard, addr + 4); stack_step(func_addr); - if (IsStackBottom(addr)) + if (IsStackBottom(guard, addr)) break; - addr = PowerPC::HostRead_U32(addr); + addr = PowerPC::HostRead_U32(guard, addr); } } } @@ -69,11 +70,12 @@ static void WalkTheStack(Core::System& system, const std::function& s // Returns callstack "formatted for debugging" - meaning that it // includes LR as the last item, and all items are the last step, // instead of "pointing ahead" -bool GetCallstack(Core::System& system, std::vector& output) +bool GetCallstack(Core::System& system, const Core::CPUThreadGuard& guard, + std::vector& output) { auto& ppc_state = system.GetPPCState(); - if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(ppc_state.gpr[1])) + if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[1])) return false; if (LR(ppc_state) == 0) @@ -91,7 +93,7 @@ bool GetCallstack(Core::System& system, std::vector& output) entry.vAddress = LR(ppc_state) - 4; output.push_back(entry); - WalkTheStack(system, [&entry, &output](u32 func_addr) { + WalkTheStack(system, guard, [&entry, &output](u32 func_addr) { std::string func_desc = g_symbolDB.GetDescription(func_addr); if (func_desc.empty() || func_desc == "Invalid") func_desc = "(unknown)"; @@ -103,7 +105,8 @@ bool GetCallstack(Core::System& system, std::vector& output) return true; } -void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level) +void PrintCallstack(Core::System& system, const Core::CPUThreadGuard& guard, + Common::Log::LogType type, Common::Log::LogLevel level) { auto& ppc_state = system.GetPPCState(); @@ -120,7 +123,7 @@ void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log LR(ppc_state)); } - WalkTheStack(system, [type, level](u32 func_addr) { + WalkTheStack(system, guard, [type, level](u32 func_addr) { std::string func_desc = g_symbolDB.GetDescription(func_addr); if (func_desc.empty() || func_desc == "Invalid") func_desc = "(unknown)"; diff --git a/Source/Core/Core/Debugger/Debugger_SymbolMap.h b/Source/Core/Core/Debugger/Debugger_SymbolMap.h index 5f334c76c8..e8408bae64 100644 --- a/Source/Core/Core/Debugger/Debugger_SymbolMap.h +++ b/Source/Core/Core/Debugger/Debugger_SymbolMap.h @@ -12,8 +12,9 @@ namespace Core { +class CPUThreadGuard; class System; -} +} // namespace Core namespace Dolphin_Debugger { @@ -23,8 +24,10 @@ struct CallstackEntry u32 vAddress = 0; }; -bool GetCallstack(Core::System& system, std::vector& output); -void PrintCallstack(Core::System& system, Common::Log::LogType type, Common::Log::LogLevel level); +bool GetCallstack(Core::System& system, const Core::CPUThreadGuard& guard, + std::vector& output); +void PrintCallstack(Core::System& system, const Core::CPUThreadGuard& guard, + Common::Log::LogType type, Common::Log::LogLevel level); void PrintDataBuffer(Common::Log::LogType type, const u8* data, size_t size, std::string_view title); void AddAutoBreakpoints(); diff --git a/Source/Core/Core/Debugger/OSThread.cpp b/Source/Core/Core/Debugger/OSThread.cpp index 86bd33dfe1..b8f3e25b6d 100644 --- a/Source/Core/Core/Debugger/OSThread.cpp +++ b/Source/Core/Core/Debugger/OSThread.cpp @@ -16,40 +16,40 @@ namespace Core::Debug // - OSDumpContext // - OSClearContext // - OSExceptionVector -void OSContext::Read(u32 addr) +void OSContext::Read(const Core::CPUThreadGuard& guard, u32 addr) { for (std::size_t i = 0; i < gpr.size(); i++) - gpr[i] = PowerPC::HostRead_U32(addr + u32(i * sizeof(int))); - cr = PowerPC::HostRead_U32(addr + 0x80); - lr = PowerPC::HostRead_U32(addr + 0x84); - ctr = PowerPC::HostRead_U32(addr + 0x88); - xer = PowerPC::HostRead_U32(addr + 0x8C); + gpr[i] = PowerPC::HostRead_U32(guard, addr + u32(i * sizeof(int))); + cr = PowerPC::HostRead_U32(guard, addr + 0x80); + lr = PowerPC::HostRead_U32(guard, addr + 0x84); + ctr = PowerPC::HostRead_U32(guard, addr + 0x88); + xer = PowerPC::HostRead_U32(guard, addr + 0x8C); for (std::size_t i = 0; i < fpr.size(); i++) - fpr[i] = PowerPC::HostRead_F64(addr + 0x90 + u32(i * sizeof(double))); - fpscr = PowerPC::HostRead_U64(addr + 0x190); - srr0 = PowerPC::HostRead_U32(addr + 0x198); - srr1 = PowerPC::HostRead_U32(addr + 0x19c); - dummy = PowerPC::HostRead_U16(addr + 0x1a0); - state = static_cast(PowerPC::HostRead_U16(addr + 0x1a2)); + fpr[i] = PowerPC::HostRead_F64(guard, addr + 0x90 + u32(i * sizeof(double))); + fpscr = PowerPC::HostRead_U64(guard, addr + 0x190); + srr0 = PowerPC::HostRead_U32(guard, addr + 0x198); + srr1 = PowerPC::HostRead_U32(guard, addr + 0x19c); + dummy = PowerPC::HostRead_U16(guard, addr + 0x1a0); + state = static_cast(PowerPC::HostRead_U16(guard, addr + 0x1a2)); for (std::size_t i = 0; i < gqr.size(); i++) - gqr[i] = PowerPC::HostRead_U32(addr + 0x1a4 + u32(i * sizeof(int))); + gqr[i] = PowerPC::HostRead_U32(guard, addr + 0x1a4 + u32(i * sizeof(int))); psf_padding = 0; for (std::size_t i = 0; i < psf.size(); i++) - psf[i] = PowerPC::HostRead_F64(addr + 0x1c8 + u32(i * sizeof(double))); + psf[i] = PowerPC::HostRead_F64(guard, addr + 0x1c8 + u32(i * sizeof(double))); } // Mutex offsets based on the following functions: // - OSInitMutex // - OSLockMutex // - __OSUnlockAllMutex -void OSMutex::Read(u32 addr) +void OSMutex::Read(const Core::CPUThreadGuard& guard, u32 addr) { - thread_queue.head = PowerPC::HostRead_U32(addr); - thread_queue.tail = PowerPC::HostRead_U32(addr + 0x4); - owner_addr = PowerPC::HostRead_U32(addr + 0x8); - lock_count = PowerPC::HostRead_U32(addr + 0xc); - link.next = PowerPC::HostRead_U32(addr + 0x10); - link.prev = PowerPC::HostRead_U32(addr + 0x14); + thread_queue.head = PowerPC::HostRead_U32(guard, addr); + thread_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x4); + owner_addr = PowerPC::HostRead_U32(guard, addr + 0x8); + lock_count = PowerPC::HostRead_U32(guard, addr + 0xc); + link.next = PowerPC::HostRead_U32(guard, addr + 0x10); + link.prev = PowerPC::HostRead_U32(guard, addr + 0x14); } // Thread offsets based on the following functions: @@ -64,46 +64,47 @@ void OSMutex::Read(u32 addr) // - __OSThreadInit // - OSSetThreadSpecific // - SOInit (for errno) -void OSThread::Read(u32 addr) +void OSThread::Read(const Core::CPUThreadGuard& guard, u32 addr) { - context.Read(addr); - state = PowerPC::HostRead_U16(addr + 0x2c8); - is_detached = PowerPC::HostRead_U16(addr + 0x2ca); - suspend = PowerPC::HostRead_U32(addr + 0x2cc); - effective_priority = PowerPC::HostRead_U32(addr + 0x2d0); - base_priority = PowerPC::HostRead_U32(addr + 0x2d4); - exit_code_addr = PowerPC::HostRead_U32(addr + 0x2d8); + context.Read(guard, addr); + state = PowerPC::HostRead_U16(guard, addr + 0x2c8); + is_detached = PowerPC::HostRead_U16(guard, addr + 0x2ca); + suspend = PowerPC::HostRead_U32(guard, addr + 0x2cc); + effective_priority = PowerPC::HostRead_U32(guard, addr + 0x2d0); + base_priority = PowerPC::HostRead_U32(guard, addr + 0x2d4); + exit_code_addr = PowerPC::HostRead_U32(guard, addr + 0x2d8); - queue_addr = PowerPC::HostRead_U32(addr + 0x2dc); - queue_link.next = PowerPC::HostRead_U32(addr + 0x2e0); - queue_link.prev = PowerPC::HostRead_U32(addr + 0x2e4); + queue_addr = PowerPC::HostRead_U32(guard, addr + 0x2dc); + queue_link.next = PowerPC::HostRead_U32(guard, addr + 0x2e0); + queue_link.prev = PowerPC::HostRead_U32(guard, addr + 0x2e4); - join_queue.head = PowerPC::HostRead_U32(addr + 0x2e8); - join_queue.tail = PowerPC::HostRead_U32(addr + 0x2ec); + join_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2e8); + join_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2ec); - mutex_addr = PowerPC::HostRead_U32(addr + 0x2f0); - mutex_queue.head = PowerPC::HostRead_U32(addr + 0x2f4); - mutex_queue.tail = PowerPC::HostRead_U32(addr + 0x2f8); + mutex_addr = PowerPC::HostRead_U32(guard, addr + 0x2f0); + mutex_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2f4); + mutex_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2f8); - thread_link.next = PowerPC::HostRead_U32(addr + 0x2fc); - thread_link.prev = PowerPC::HostRead_U32(addr + 0x300); + thread_link.next = PowerPC::HostRead_U32(guard, addr + 0x2fc); + thread_link.prev = PowerPC::HostRead_U32(guard, addr + 0x300); - stack_addr = PowerPC::HostRead_U32(addr + 0x304); - stack_end = PowerPC::HostRead_U32(addr + 0x308); - error = PowerPC::HostRead_U32(addr + 0x30c); - specific[0] = PowerPC::HostRead_U32(addr + 0x310); - specific[1] = PowerPC::HostRead_U32(addr + 0x314); + stack_addr = PowerPC::HostRead_U32(guard, addr + 0x304); + stack_end = PowerPC::HostRead_U32(guard, addr + 0x308); + error = PowerPC::HostRead_U32(guard, addr + 0x30c); + specific[0] = PowerPC::HostRead_U32(guard, addr + 0x310); + specific[1] = PowerPC::HostRead_U32(guard, addr + 0x314); } -bool OSThread::IsValid() const +bool OSThread::IsValid(const Core::CPUThreadGuard& guard) const { - return PowerPC::HostIsRAMAddress(stack_end) && PowerPC::HostRead_U32(stack_end) == STACK_MAGIC; + return PowerPC::HostIsRAMAddress(guard, stack_end) && + PowerPC::HostRead_U32(guard, stack_end) == STACK_MAGIC; } -OSThreadView::OSThreadView(u32 addr) +OSThreadView::OSThreadView(const Core::CPUThreadGuard& guard, u32 addr) { m_address = addr; - m_thread.Read(addr); + m_thread.Read(guard, addr); } const OSThread& OSThreadView::Data() const @@ -111,11 +112,11 @@ const OSThread& OSThreadView::Data() const return m_thread; } -Common::Debug::PartialContext OSThreadView::GetContext() const +Common::Debug::PartialContext OSThreadView::GetContext(const Core::CPUThreadGuard& guard) const { Common::Debug::PartialContext context; - if (!IsValid()) + if (!IsValid(guard)) return context; context.gpr = m_thread.context.gpr; @@ -185,23 +186,23 @@ s32 OSThreadView::GetErrno() const return m_thread.error; } -std::string OSThreadView::GetSpecific() const +std::string OSThreadView::GetSpecific(const Core::CPUThreadGuard& guard) const { std::string specific; for (u32 addr : m_thread.specific) { - if (!PowerPC::HostIsRAMAddress(addr)) + if (!PowerPC::HostIsRAMAddress(guard, addr)) break; - specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(addr)); + specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(guard, addr)); } return specific; } -bool OSThreadView::IsValid() const +bool OSThreadView::IsValid(const Core::CPUThreadGuard& guard) const { - return m_thread.IsValid(); + return m_thread.IsValid(guard); } } // namespace Core::Debug diff --git a/Source/Core/Core/Debugger/OSThread.h b/Source/Core/Core/Debugger/OSThread.h index 16142bba60..309df3eb52 100644 --- a/Source/Core/Core/Debugger/OSThread.h +++ b/Source/Core/Core/Debugger/OSThread.h @@ -10,6 +10,11 @@ #include "Common/CommonTypes.h" #include "Common/Debug/Threads.h" +namespace Core +{ +class CPUThreadGuard; +}; + namespace Core::Debug { template @@ -56,7 +61,7 @@ struct OSContext u32 psf_padding; std::array psf; - void Read(u32 addr); + void Read(const Core::CPUThreadGuard& guard, u32 addr); }; static_assert(std::is_trivially_copyable_v); @@ -96,8 +101,8 @@ struct OSThread std::array specific; // Pointers to data (can be used to store thread names) static constexpr u32 STACK_MAGIC = 0xDEADBABE; - void Read(u32 addr); - bool IsValid() const; + void Read(const Core::CPUThreadGuard& guard, u32 addr); + bool IsValid(const Core::CPUThreadGuard& guard) const; }; static_assert(std::is_trivially_copyable_v); @@ -115,7 +120,7 @@ struct OSMutex OSMutexLink link; // Used to traverse the thread's mutex queue // OSLockMutex uses it to insert the acquired mutex at the end of the queue - void Read(u32 addr); + void Read(const Core::CPUThreadGuard& guard, u32 addr); }; static_assert(std::is_trivially_copyable_v); @@ -126,12 +131,12 @@ static_assert(offsetof(OSMutex, link) == 0x10); class OSThreadView : public Common::Debug::ThreadView { public: - explicit OSThreadView(u32 addr); + explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr); ~OSThreadView() = default; const OSThread& Data() const; - Common::Debug::PartialContext GetContext() const override; + Common::Debug::PartialContext GetContext(const Core::CPUThreadGuard& guard) const override; u32 GetAddress() const override; u16 GetState() const override; bool IsSuspended() const override; @@ -142,8 +147,8 @@ public: u32 GetStackEnd() const override; std::size_t GetStackSize() const override; s32 GetErrno() const override; - std::string GetSpecific() const override; - bool IsValid() const override; + std::string GetSpecific(const Core::CPUThreadGuard& guard) const override; + bool IsValid(const Core::CPUThreadGuard& guard) const override; private: u32 m_address = 0; diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 96ee849d50..8258119c12 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -25,27 +25,28 @@ #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" -void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value) +void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPatch& patch, + bool store_existing_value) { if (patch.value.empty()) return; const u32 address = patch.address; const std::size_t size = patch.value.size(); - if (!PowerPC::HostIsRAMAddress(address)) + if (!PowerPC::HostIsRAMAddress(guard, address)) return; for (u32 offset = 0; offset < size; ++offset) { if (store_existing_value) { - const u8 value = PowerPC::HostRead_U8(address + offset); - PowerPC::HostWrite_U8(patch.value[offset], address + offset); + const u8 value = PowerPC::HostRead_U8(guard, address + offset); + PowerPC::HostWrite_U8(guard, patch.value[offset], address + offset); patch.value[offset] = value; } else { - PowerPC::HostWrite_U8(patch.value[offset], address + offset); + PowerPC::HostWrite_U8(guard, patch.value[offset], address + offset); } if (((address + offset) % 4) == 3) @@ -58,17 +59,17 @@ void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_val } } -void PPCPatches::ApplyExistingPatch(std::size_t index) +void PPCPatches::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) { auto& patch = m_patches[index]; - ApplyMemoryPatch(patch, false); + ApplyMemoryPatch(guard, patch, false); } -void PPCPatches::Patch(std::size_t index) +void PPCPatches::Patch(const Core::CPUThreadGuard& guard, std::size_t index) { auto& patch = m_patches[index]; if (patch.type == Common::Debug::MemoryPatch::ApplyType::Once) - ApplyMemoryPatch(patch); + ApplyMemoryPatch(guard, patch); else PatchEngine::AddMemoryPatch(index); } @@ -163,24 +164,26 @@ void PPCDebugInterface::ClearWatches() m_watches.Clear(); } -void PPCDebugInterface::SetPatch(u32 address, u32 value) +void PPCDebugInterface::SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { - m_patches.SetPatch(address, value); + m_patches.SetPatch(guard, address, value); } -void PPCDebugInterface::SetPatch(u32 address, std::vector value) +void PPCDebugInterface::SetPatch(const Core::CPUThreadGuard& guard, u32 address, + std::vector value) { - m_patches.SetPatch(address, std::move(value)); + m_patches.SetPatch(guard, address, std::move(value)); } -void PPCDebugInterface::SetFramePatch(u32 address, u32 value) +void PPCDebugInterface::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { - m_patches.SetFramePatch(address, value); + m_patches.SetFramePatch(guard, address, value); } -void PPCDebugInterface::SetFramePatch(u32 address, std::vector value) +void PPCDebugInterface::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, + std::vector value) { - m_patches.SetFramePatch(address, std::move(value)); + m_patches.SetFramePatch(guard, address, std::move(value)); } const std::vector& PPCDebugInterface::GetPatches() const @@ -188,19 +191,19 @@ const std::vector& PPCDebugInterface::GetPatches() c return m_patches.GetPatches(); } -void PPCDebugInterface::UnsetPatch(u32 address) +void PPCDebugInterface::UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) { - m_patches.UnsetPatch(address); + m_patches.UnsetPatch(guard, address); } -void PPCDebugInterface::EnablePatch(std::size_t index) +void PPCDebugInterface::EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { - m_patches.EnablePatch(index); + m_patches.EnablePatch(guard, index); } -void PPCDebugInterface::DisablePatch(std::size_t index) +void PPCDebugInterface::DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { - m_patches.DisablePatch(index); + m_patches.DisablePatch(guard, index); } bool PPCDebugInterface::HasEnabledPatch(u32 address) const @@ -208,45 +211,45 @@ bool PPCDebugInterface::HasEnabledPatch(u32 address) const return m_patches.HasEnabledPatch(address); } -void PPCDebugInterface::RemovePatch(std::size_t index) +void PPCDebugInterface::RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) { - m_patches.RemovePatch(index); + m_patches.RemovePatch(guard, index); } -void PPCDebugInterface::ClearPatches() +void PPCDebugInterface::ClearPatches(const Core::CPUThreadGuard& guard) { - m_patches.ClearPatches(); + m_patches.ClearPatches(guard); } -void PPCDebugInterface::ApplyExistingPatch(std::size_t index) +void PPCDebugInterface::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) { - m_patches.ApplyExistingPatch(index); + m_patches.ApplyExistingPatch(guard, index); } -Common::Debug::Threads PPCDebugInterface::GetThreads() const +Common::Debug::Threads PPCDebugInterface::GetThreads(const Core::CPUThreadGuard& guard) const { Common::Debug::Threads threads; constexpr u32 ACTIVE_QUEUE_HEAD_ADDR = 0x800000dc; - if (!PowerPC::HostIsRAMAddress(ACTIVE_QUEUE_HEAD_ADDR)) + if (!PowerPC::HostIsRAMAddress(guard, ACTIVE_QUEUE_HEAD_ADDR)) return threads; - const u32 active_queue_head = PowerPC::HostRead_U32(ACTIVE_QUEUE_HEAD_ADDR); - if (!PowerPC::HostIsRAMAddress(active_queue_head)) + const u32 active_queue_head = PowerPC::HostRead_U32(guard, ACTIVE_QUEUE_HEAD_ADDR); + if (!PowerPC::HostIsRAMAddress(guard, active_queue_head)) return threads; - auto active_thread = std::make_unique(active_queue_head); - if (!active_thread->IsValid()) + auto active_thread = std::make_unique(guard, active_queue_head); + if (!active_thread->IsValid(guard)) return threads; std::vector visited_addrs{active_thread->GetAddress()}; - const auto insert_threads = [&threads, &visited_addrs](u32 addr, auto get_next_addr) { - while (addr != 0 && PowerPC::HostIsRAMAddress(addr)) + const auto insert_threads = [&guard, &threads, &visited_addrs](u32 addr, auto get_next_addr) { + while (addr != 0 && PowerPC::HostIsRAMAddress(guard, addr)) { if (std::find(visited_addrs.begin(), visited_addrs.end(), addr) != visited_addrs.end()) break; visited_addrs.push_back(addr); - auto thread = std::make_unique(addr); - if (!thread->IsValid()) + auto thread = std::make_unique(guard, addr); + if (!thread->IsValid(guard)) break; addr = get_next_addr(*thread); threads.emplace_back(std::move(thread)); @@ -264,20 +267,16 @@ Common::Debug::Threads PPCDebugInterface::GetThreads() const return threads; } -std::string PPCDebugInterface::Disassemble(u32 address) const +std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address) const { - // PowerPC::HostRead_U32 seemed to crash on shutdown - if (!IsAlive()) - return ""; - - if (Core::GetState() == Core::State::Paused) + if (guard) { - if (!PowerPC::HostIsRAMAddress(address)) + if (!PowerPC::HostIsRAMAddress(*guard, address)) { return "(No RAM here)"; } - const u32 op = PowerPC::HostRead_Instruction(address); + const u32 op = PowerPC::HostRead_Instruction(*guard, address); std::string disasm = Common::GekkoDisassembler::Disassemble(op, address); const UGeckoInstruction inst{op}; @@ -294,14 +293,18 @@ std::string PPCDebugInterface::Disassemble(u32 address) const } } -std::string PPCDebugInterface::GetRawMemoryString(int memory, u32 address) const +std::string PPCDebugInterface::GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory, + u32 address) const { if (IsAlive()) { const bool is_aram = memory != 0; - if (is_aram || PowerPC::HostIsRAMAddress(address)) - return fmt::format("{:08X}{}", ReadExtraMemory(memory, address), is_aram ? " (ARAM)" : ""); + if (is_aram || PowerPC::HostIsRAMAddress(guard, address)) + { + return fmt::format("{:08X}{}", ReadExtraMemory(guard, memory, address), + is_aram ? " (ARAM)" : ""); + } return is_aram ? "--ARAM--" : "--------"; } @@ -309,17 +312,18 @@ std::string PPCDebugInterface::GetRawMemoryString(int memory, u32 address) const return ""; // bad spelling - 8 chars } -u32 PPCDebugInterface::ReadMemory(u32 address) const +u32 PPCDebugInterface::ReadMemory(const Core::CPUThreadGuard& guard, u32 address) const { - return PowerPC::HostRead_U32(address); + return PowerPC::HostRead_U32(guard, address); } -u32 PPCDebugInterface::ReadExtraMemory(int memory, u32 address) const +u32 PPCDebugInterface::ReadExtraMemory(const Core::CPUThreadGuard& guard, int memory, + u32 address) const { switch (memory) { case 0: - return PowerPC::HostRead_U32(address); + return PowerPC::HostRead_U32(guard, address); case 1: return (DSP::ReadARAM(address) << 24) | (DSP::ReadARAM(address + 1) << 16) | (DSP::ReadARAM(address + 2) << 8) | (DSP::ReadARAM(address + 3)); @@ -328,9 +332,9 @@ u32 PPCDebugInterface::ReadExtraMemory(int memory, u32 address) const } } -u32 PPCDebugInterface::ReadInstruction(u32 address) const +u32 PPCDebugInterface::ReadInstruction(const Core::CPUThreadGuard& guard, u32 address) const { - return PowerPC::HostRead_Instruction(address); + return PowerPC::HostRead_Instruction(guard, address); } bool PPCDebugInterface::IsAlive() const @@ -401,11 +405,11 @@ void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool // ======================================================= // Separate the blocks with colors. // ------------- -u32 PPCDebugInterface::GetColor(u32 address) const +u32 PPCDebugInterface::GetColor(const Core::CPUThreadGuard* guard, u32 address) const { - if (!IsAlive()) + if (!guard || !IsAlive()) return 0xFFFFFF; - if (!PowerPC::HostIsRAMAddress(address)) + if (!PowerPC::HostIsRAMAddress(*guard, address)) return 0xeeeeee; Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address); @@ -525,11 +529,11 @@ std::shared_ptr PPCDebugInterface::NetworkLogger() return m_network_logger; } -void PPCDebugInterface::Clear() +void PPCDebugInterface::Clear(const Core::CPUThreadGuard& guard) { ClearAllBreakpoints(); ClearAllMemChecks(); - ClearPatches(); + ClearPatches(guard); ClearWatches(); m_network_logger.reset(); } diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index 118874fe21..9be57200b9 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -14,18 +14,20 @@ namespace Core { +class CPUThreadGuard; class System; -} +} // namespace Core -void ApplyMemoryPatch(Common::Debug::MemoryPatch& patch, bool store_existing_value = true); +void ApplyMemoryPatch(const Core::CPUThreadGuard&, Common::Debug::MemoryPatch& patch, + bool store_existing_value = true); class PPCPatches final : public Common::Debug::MemoryPatches { public: - void ApplyExistingPatch(std::size_t index) override; + void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) override; private: - void Patch(std::size_t index) override; + void Patch(const Core::CPUThreadGuard& guard, std::size_t index) override; void UnPatch(std::size_t index) override; }; @@ -55,24 +57,26 @@ public: void ClearWatches() override; // Memory Patches - void SetPatch(u32 address, u32 value) override; - void SetPatch(u32 address, std::vector value) override; - void SetFramePatch(u32 address, u32 value) override; - void SetFramePatch(u32 address, std::vector value) override; + void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) override; + void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value) override; + void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) override; + void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, + std::vector value) override; const std::vector& GetPatches() const override; - void UnsetPatch(u32 address) override; - void EnablePatch(std::size_t index) override; - void DisablePatch(std::size_t index) override; + void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) override; + void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) override; + void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) override; bool HasEnabledPatch(u32 address) const override; - void RemovePatch(std::size_t index) override; - void ClearPatches() override; - void ApplyExistingPatch(std::size_t index) override; + void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) override; + void ClearPatches(const Core::CPUThreadGuard& guard) override; + void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) override; // Threads - Common::Debug::Threads GetThreads() const override; + Common::Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const override; - std::string Disassemble(u32 address) const override; - std::string GetRawMemoryString(int memory, u32 address) const override; + std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address) const override; + std::string GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory, + u32 address) const override; bool IsAlive() const override; bool IsBreakpoint(u32 address) const override; void SetBreakpoint(u32 address) override; @@ -82,26 +86,26 @@ public: void ClearAllMemChecks() override; bool IsMemCheck(u32 address, size_t size = 1) const override; void ToggleMemCheck(u32 address, bool read = true, bool write = true, bool log = true) override; - u32 ReadMemory(u32 address) const override; + u32 ReadMemory(const Core::CPUThreadGuard& guard, u32 address) const override; enum { EXTRAMEM_ARAM = 1, }; - u32 ReadExtraMemory(int memory, u32 address) const override; - u32 ReadInstruction(u32 address) const override; + u32 ReadExtraMemory(const Core::CPUThreadGuard& guard, int memory, u32 address) const override; + u32 ReadInstruction(const Core::CPUThreadGuard& guard, u32 address) const override; std::optional GetMemoryAddressFromInstruction(const std::string& instruction) const override; u32 GetPC() const override; void SetPC(u32 address) override; void Step() override {} void RunToBreakpoint() override; - u32 GetColor(u32 address) const override; + u32 GetColor(const Core::CPUThreadGuard* guard, u32 address) const override; std::string GetDescription(u32 address) const override; std::shared_ptr NetworkLogger(); - void Clear() override; + void Clear(const Core::CPUThreadGuard& guard) override; private: Common::Debug::Watches m_watches; diff --git a/Source/Core/Core/Debugger/RSO.cpp b/Source/Core/Core/Debugger/RSO.cpp index 51a589856c..319e1962c8 100644 --- a/Source/Core/Core/Debugger/RSO.cpp +++ b/Source/Core/Core/Debugger/RSO.cpp @@ -14,40 +14,40 @@ #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PPCSymbolDB.h" -void RSOHeaderView::Load(u32 address) +void RSOHeaderView::Load(const Core::CPUThreadGuard& guard, u32 address) { m_address = address; - m_header.entry.next_entry = PowerPC::HostRead_U32(address); - m_header.entry.prev_entry = PowerPC::HostRead_U32(address + 0x04); - m_header.entry.section_count = PowerPC::HostRead_U32(address + 0x08); - m_header.entry.section_table_offset = PowerPC::HostRead_U32(address + 0xC); - m_header.entry.name_offset = PowerPC::HostRead_U32(address + 0x10); - m_header.entry.name_size = PowerPC::HostRead_U32(address + 0x14); - m_header.entry.version = PowerPC::HostRead_U32(address + 0x18); - m_header.entry.bss_size = PowerPC::HostRead_U32(address + 0x1C); - m_header.section_info.prolog_section_index = PowerPC::HostRead_U8(address + 0x20); - m_header.section_info.epilog_section_index = PowerPC::HostRead_U8(address + 0x21); - m_header.section_info.unresolved_section_index = PowerPC::HostRead_U8(address + 0x22); - m_header.section_info.bss_section_index = PowerPC::HostRead_U8(address + 0x23); - m_header.section_info.prolog_offset = PowerPC::HostRead_U32(address + 0x24); - m_header.section_info.epilog_offset = PowerPC::HostRead_U32(address + 0x28); - m_header.section_info.unresolved_offset = PowerPC::HostRead_U32(address + 0x2C); - m_header.relocation_tables.internals_offset = PowerPC::HostRead_U32(address + 0x30); - m_header.relocation_tables.internals_size = PowerPC::HostRead_U32(address + 0x34); - m_header.relocation_tables.externals_offset = PowerPC::HostRead_U32(address + 0x38); - m_header.relocation_tables.externals_size = PowerPC::HostRead_U32(address + 0x3C); - m_header.symbol_tables.exports_offset = PowerPC::HostRead_U32(address + 0x40); - m_header.symbol_tables.exports_size = PowerPC::HostRead_U32(address + 0x44); - m_header.symbol_tables.exports_name_table = PowerPC::HostRead_U32(address + 0x48); - m_header.symbol_tables.imports_offset = PowerPC::HostRead_U32(address + 0x4C); - m_header.symbol_tables.imports_size = PowerPC::HostRead_U32(address + 0x50); - m_header.symbol_tables.imports_name_table = PowerPC::HostRead_U32(address + 0x54); + m_header.entry.next_entry = PowerPC::HostRead_U32(guard, address); + m_header.entry.prev_entry = PowerPC::HostRead_U32(guard, address + 0x04); + m_header.entry.section_count = PowerPC::HostRead_U32(guard, address + 0x08); + m_header.entry.section_table_offset = PowerPC::HostRead_U32(guard, address + 0xC); + m_header.entry.name_offset = PowerPC::HostRead_U32(guard, address + 0x10); + m_header.entry.name_size = PowerPC::HostRead_U32(guard, address + 0x14); + m_header.entry.version = PowerPC::HostRead_U32(guard, address + 0x18); + m_header.entry.bss_size = PowerPC::HostRead_U32(guard, address + 0x1C); + m_header.section_info.prolog_section_index = PowerPC::HostRead_U8(guard, address + 0x20); + m_header.section_info.epilog_section_index = PowerPC::HostRead_U8(guard, address + 0x21); + m_header.section_info.unresolved_section_index = PowerPC::HostRead_U8(guard, address + 0x22); + m_header.section_info.bss_section_index = PowerPC::HostRead_U8(guard, address + 0x23); + m_header.section_info.prolog_offset = PowerPC::HostRead_U32(guard, address + 0x24); + m_header.section_info.epilog_offset = PowerPC::HostRead_U32(guard, address + 0x28); + m_header.section_info.unresolved_offset = PowerPC::HostRead_U32(guard, address + 0x2C); + m_header.relocation_tables.internals_offset = PowerPC::HostRead_U32(guard, address + 0x30); + m_header.relocation_tables.internals_size = PowerPC::HostRead_U32(guard, address + 0x34); + m_header.relocation_tables.externals_offset = PowerPC::HostRead_U32(guard, address + 0x38); + m_header.relocation_tables.externals_size = PowerPC::HostRead_U32(guard, address + 0x3C); + m_header.symbol_tables.exports_offset = PowerPC::HostRead_U32(guard, address + 0x40); + m_header.symbol_tables.exports_size = PowerPC::HostRead_U32(guard, address + 0x44); + m_header.symbol_tables.exports_name_table = PowerPC::HostRead_U32(guard, address + 0x48); + m_header.symbol_tables.imports_offset = PowerPC::HostRead_U32(guard, address + 0x4C); + m_header.symbol_tables.imports_size = PowerPC::HostRead_U32(guard, address + 0x50); + m_header.symbol_tables.imports_name_table = PowerPC::HostRead_U32(guard, address + 0x54); // Prevent an invalid name going wild if (m_header.entry.name_size < 0x100) - m_name = PowerPC::HostGetString(m_header.entry.name_offset, m_header.entry.name_size); + m_name = PowerPC::HostGetString(guard, m_header.entry.name_offset, m_header.entry.name_size); else - m_name = PowerPC::HostGetString(m_header.entry.name_offset, 0x100); + m_name = PowerPC::HostGetString(guard, m_header.entry.name_offset, 0x100); } u32 RSOHeaderView::GetNextEntry() const @@ -170,14 +170,14 @@ u32 RSOHeaderView::GetImportsNameTable() const return m_header.symbol_tables.imports_name_table; } -void RSOSectionsView::Load(u32 address, std::size_t count) +void RSOSectionsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count) { m_address = address; for (std::size_t i = 0; i < count; ++i) { RSOSection section; - section.offset = PowerPC::HostRead_U32(address); - section.size = PowerPC::HostRead_U32(address + 4); + section.offset = PowerPC::HostRead_U32(guard, address); + section.size = PowerPC::HostRead_U32(guard, address + 4); m_sections.emplace_back(std::move(section)); address += sizeof(RSOSection); } @@ -198,15 +198,15 @@ const std::vector& RSOSectionsView::GetSections() const return m_sections; } -void RSOImportsView::Load(u32 address, std::size_t count) +void RSOImportsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count) { m_address = address; for (std::size_t i = 0; i < count; ++i) { RSOImport rso_import; - rso_import.name_offset = PowerPC::HostRead_U32(address); - rso_import.code_offset = PowerPC::HostRead_U32(address + 4); - rso_import.entry_offset = PowerPC::HostRead_U32(address + 8); + rso_import.name_offset = PowerPC::HostRead_U32(guard, address); + rso_import.code_offset = PowerPC::HostRead_U32(guard, address + 4); + rso_import.entry_offset = PowerPC::HostRead_U32(guard, address + 8); m_imports.emplace_back(std::move(rso_import)); address += sizeof(RSOImport); } @@ -227,16 +227,16 @@ const std::vector& RSOImportsView::GetImports() const return m_imports; } -void RSOExportsView::Load(u32 address, std::size_t count) +void RSOExportsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count) { m_address = address; for (std::size_t i = 0; i < count; ++i) { RSOExport rso_export; - rso_export.name_offset = PowerPC::HostRead_U32(address); - rso_export.code_offset = PowerPC::HostRead_U32(address + 4); - rso_export.section_index = PowerPC::HostRead_U32(address + 8); - rso_export.hash = PowerPC::HostRead_U32(address + 12); + rso_export.name_offset = PowerPC::HostRead_U32(guard, address); + rso_export.code_offset = PowerPC::HostRead_U32(guard, address + 4); + rso_export.section_index = PowerPC::HostRead_U32(guard, address + 8); + rso_export.hash = PowerPC::HostRead_U32(guard, address + 12); m_exports.emplace_back(std::move(rso_export)); address += sizeof(RSOExport); } @@ -257,15 +257,15 @@ const std::vector& RSOExportsView::GetExports() const return m_exports; } -void RSOInternalsView::Load(u32 address, std::size_t count) +void RSOInternalsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count) { m_address = address; for (std::size_t i = 0; i < count; ++i) { RSOInternalsEntry entry; - entry.r_offset = PowerPC::HostRead_U32(address); - entry.r_info = PowerPC::HostRead_U32(address + 4); - entry.r_addend = PowerPC::HostRead_U32(address + 8); + entry.r_offset = PowerPC::HostRead_U32(guard, address); + entry.r_info = PowerPC::HostRead_U32(guard, address + 4); + entry.r_addend = PowerPC::HostRead_U32(guard, address + 8); m_entries.emplace_back(std::move(entry)); address += sizeof(RSOInternalsEntry); } @@ -286,15 +286,15 @@ const std::vector& RSOInternalsView::GetEntries() const return m_entries; } -void RSOExternalsView::Load(u32 address, std::size_t count) +void RSOExternalsView::Load(const Core::CPUThreadGuard& guard, u32 address, std::size_t count) { m_address = address; for (std::size_t i = 0; i < count; ++i) { RSOExternalsEntry entry; - entry.r_offset = PowerPC::HostRead_U32(address); - entry.r_info = PowerPC::HostRead_U32(address + 4); - entry.r_addend = PowerPC::HostRead_U32(address + 8); + entry.r_offset = PowerPC::HostRead_U32(guard, address); + entry.r_info = PowerPC::HostRead_U32(guard, address + 4); + entry.r_addend = PowerPC::HostRead_U32(guard, address + 8); m_entries.emplace_back(std::move(entry)); address += sizeof(RSOExternalsEntry); } @@ -315,71 +315,71 @@ const std::vector& RSOExternalsView::GetEntries() const return m_entries; } -void RSOView::LoadHeader(u32 address) +void RSOView::LoadHeader(const Core::CPUThreadGuard& guard, u32 address) { m_address = address; - m_header.Load(address); + m_header.Load(guard, address); } -void RSOView::LoadSections() +void RSOView::LoadSections(const Core::CPUThreadGuard& guard) { - m_sections.Load(m_header.GetSectionTableOffset(), m_header.GetSectionCount()); + m_sections.Load(guard, m_header.GetSectionTableOffset(), m_header.GetSectionCount()); } -void RSOView::LoadImports() +void RSOView::LoadImports(const Core::CPUThreadGuard& guard) { const std::size_t size = m_header.GetImportsSize(); if (size % sizeof(RSOImport) != 0) WARN_LOG_FMT(SYMBOLS, "RSO Imports Table has an incoherent size ({:08x})", size); - m_imports.Load(m_header.GetImportsOffset(), size / sizeof(RSOImport)); + m_imports.Load(guard, m_header.GetImportsOffset(), size / sizeof(RSOImport)); } -void RSOView::LoadExports() +void RSOView::LoadExports(const Core::CPUThreadGuard& guard) { const std::size_t size = m_header.GetExportsSize(); if (size % sizeof(RSOExport) != 0) WARN_LOG_FMT(SYMBOLS, "RSO Exports Table has an incoherent size ({:08x})", size); - m_exports.Load(m_header.GetExportsOffset(), size / sizeof(RSOExport)); + m_exports.Load(guard, m_header.GetExportsOffset(), size / sizeof(RSOExport)); } -void RSOView::LoadInternals() +void RSOView::LoadInternals(const Core::CPUThreadGuard& guard) { const std::size_t size = m_header.GetInternalsSize(); if (size % sizeof(RSOInternalsEntry) != 0) WARN_LOG_FMT(SYMBOLS, "RSO Internals Relocation Table has an incoherent size ({:08x})", size); - m_imports.Load(m_header.GetInternalsOffset(), size / sizeof(RSOInternalsEntry)); + m_imports.Load(guard, m_header.GetInternalsOffset(), size / sizeof(RSOInternalsEntry)); } -void RSOView::LoadExternals() +void RSOView::LoadExternals(const Core::CPUThreadGuard& guard) { const std::size_t size = m_header.GetExternalsSize(); if (size % sizeof(RSOExternalsEntry) != 0) WARN_LOG_FMT(SYMBOLS, "RSO Externals Relocation Table has an incoherent size ({:08x})", size); - m_imports.Load(m_header.GetExternalsOffset(), size / sizeof(RSOExternalsEntry)); + m_imports.Load(guard, m_header.GetExternalsOffset(), size / sizeof(RSOExternalsEntry)); } -void RSOView::LoadAll(u32 address) +void RSOView::LoadAll(const Core::CPUThreadGuard& guard, u32 address) { - LoadHeader(address); - LoadSections(); - LoadImports(); - LoadExports(); - LoadInternals(); - LoadExternals(); + LoadHeader(guard, address); + LoadSections(guard); + LoadImports(guard); + LoadExports(guard); + LoadInternals(guard); + LoadExternals(guard); } -void RSOView::Apply(PPCSymbolDB* symbol_db) const +void RSOView::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const { for (const RSOExport& rso_export : GetExports()) { u32 address = GetExportAddress(rso_export); if (address != 0) { - Common::Symbol* symbol = symbol_db->AddFunction(address); + Common::Symbol* symbol = symbol_db->AddFunction(guard, address); if (!symbol) symbol = symbol_db->GetSymbolFromAddr(address); - const std::string export_name = GetExportName(rso_export); + const std::string export_name = GetExportName(guard, rso_export); if (symbol) { // Function symbol @@ -388,7 +388,7 @@ void RSOView::Apply(PPCSymbolDB* symbol_db) const else { // Data symbol - symbol_db->AddKnownSymbol(address, 0, export_name, Common::Symbol::Type::Data); + symbol_db->AddKnownSymbol(guard, address, 0, export_name, Common::Symbol::Type::Data); } } } @@ -440,9 +440,10 @@ const RSOImport& RSOView::GetImport(std::size_t index) const return m_imports.GetImport(index); } -std::string RSOView::GetImportName(const RSOImport& rso_import) const +std::string RSOView::GetImportName(const Core::CPUThreadGuard& guard, + const RSOImport& rso_import) const { - return PowerPC::HostGetString(m_header.GetImportsNameTable() + rso_import.name_offset); + return PowerPC::HostGetString(guard, m_header.GetImportsNameTable() + rso_import.name_offset); } const std::vector& RSOView::GetImports() const @@ -460,9 +461,10 @@ const RSOExport& RSOView::GetExport(std::size_t index) const return m_exports.GetExport(index); } -std::string RSOView::GetExportName(const RSOExport& rso_export) const +std::string RSOView::GetExportName(const Core::CPUThreadGuard& guard, + const RSOExport& rso_export) const { - return PowerPC::HostGetString(m_header.GetExportsNameTable() + rso_export.name_offset); + return PowerPC::HostGetString(guard, m_header.GetExportsNameTable() + rso_export.name_offset); } u32 RSOView::GetExportAddress(const RSOExport& rso_export) const @@ -515,14 +517,14 @@ const std::string& RSOView::GetName() const return m_header.GetName(); } -std::string RSOView::GetName(const RSOImport& rso_import) const +std::string RSOView::GetName(const Core::CPUThreadGuard& guard, const RSOImport& rso_import) const { - return GetImportName(rso_import); + return GetImportName(guard, rso_import); } -std::string RSOView::GetName(const RSOExport& rso_export) const +std::string RSOView::GetName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const { - return GetExportName(rso_export); + return GetExportName(guard, rso_export); } u32 RSOView::GetProlog() const @@ -561,33 +563,33 @@ u32 RSOView::GetUnresolved() const return 0; } -bool RSOChainView::Load(u32 address) +bool RSOChainView::Load(const Core::CPUThreadGuard& guard, u32 address) { // Load node RSOView node; - node.LoadHeader(address); + node.LoadHeader(guard, address); DEBUG_LOG_FMT(SYMBOLS, "RSOChain node name: {}", node.GetName()); m_chain.emplace_front(std::move(node)); - if (LoadNextChain(m_chain.front()) && LoadPrevChain(m_chain.front())) + if (LoadNextChain(guard, m_chain.front()) && LoadPrevChain(guard, m_chain.front())) { for (RSOView& view : m_chain) { - view.LoadSections(); - view.LoadExports(); - view.LoadImports(); - view.LoadExternals(); - view.LoadInternals(); + view.LoadSections(guard); + view.LoadExports(guard); + view.LoadImports(guard); + view.LoadExternals(guard); + view.LoadInternals(guard); } return true; } return false; } -void RSOChainView::Apply(PPCSymbolDB* symbol_db) const +void RSOChainView::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const { for (const RSOView& rso_view : m_chain) - rso_view.Apply(symbol_db); + rso_view.Apply(guard, symbol_db); } void RSOChainView::Clear() @@ -600,7 +602,7 @@ const std::list& RSOChainView::GetChain() const return m_chain; } -bool RSOChainView::LoadNextChain(const RSOView& view) +bool RSOChainView::LoadNextChain(const Core::CPUThreadGuard& guard, const RSOView& view) { u32 prev_address = view.GetAddress(); u32 next_address = view.GetNextEntry(); @@ -608,7 +610,7 @@ bool RSOChainView::LoadNextChain(const RSOView& view) while (next_address != 0) { RSOView next_node; - next_node.LoadHeader(next_address); + next_node.LoadHeader(guard, next_address); if (prev_address != next_node.GetPrevEntry()) { @@ -625,7 +627,7 @@ bool RSOChainView::LoadNextChain(const RSOView& view) return true; } -bool RSOChainView::LoadPrevChain(const RSOView& view) +bool RSOChainView::LoadPrevChain(const Core::CPUThreadGuard& guard, const RSOView& view) { u32 prev_address = view.GetPrevEntry(); u32 next_address = view.GetAddress(); @@ -633,7 +635,7 @@ bool RSOChainView::LoadPrevChain(const RSOView& view) while (prev_address != 0) { RSOView prev_node; - prev_node.LoadHeader(prev_address); + prev_node.LoadHeader(guard, prev_address); if (next_address != prev_node.GetNextEntry()) { diff --git a/Source/Core/Core/Debugger/RSO.h b/Source/Core/Core/Debugger/RSO.h index dc5d61e8ab..b1e0ac0a98 100644 --- a/Source/Core/Core/Debugger/RSO.h +++ b/Source/Core/Core/Debugger/RSO.h @@ -13,6 +13,11 @@ class PPCSymbolDB; +namespace Core +{ +class CPUThreadGuard; +}; + struct RSOEntry { u32 next_entry; @@ -103,7 +108,7 @@ using RSOExternalsEntry = RSORelocationTableEntry& GetImports() const; std::size_t GetExportsCount() const; const RSOExport& GetExport(std::size_t index) const; - std::string GetExportName(const RSOExport& rso_export) const; + std::string GetExportName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const; u32 GetExportAddress(const RSOExport& rso_export) const; const std::vector& GetExports() const; @@ -248,8 +253,8 @@ public: const std::vector& GetExternals() const; const std::string& GetName() const; - std::string GetName(const RSOImport& rso_import) const; - std::string GetName(const RSOExport& rso_export) const; + std::string GetName(const Core::CPUThreadGuard& guard, const RSOImport& rso_import) const; + std::string GetName(const Core::CPUThreadGuard& guard, const RSOExport& rso_export) const; u32 GetProlog() const; u32 GetEpilog() const; @@ -268,14 +273,14 @@ private: class RSOChainView { public: - bool Load(u32 address); - void Apply(PPCSymbolDB* symbol_db) const; + bool Load(const Core::CPUThreadGuard& guard, u32 address); + void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const; void Clear(); const std::list& GetChain() const; private: - bool LoadNextChain(const RSOView& view); - bool LoadPrevChain(const RSOView& view); + bool LoadNextChain(const Core::CPUThreadGuard& guard, const RSOView& view); + bool LoadPrevChain(const Core::CPUThreadGuard& guard, const RSOView& view); std::list m_chain; }; diff --git a/Source/Core/Core/GeckoCode.cpp b/Source/Core/Core/GeckoCode.cpp index be5ce914db..f77f09203f 100644 --- a/Source/Core/Core/GeckoCode.cpp +++ b/Source/Core/Core/GeckoCode.cpp @@ -118,7 +118,7 @@ std::vector SetAndReturnActiveCodes(std::span 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. " diff --git a/Source/Core/Core/GeckoCode.h b/Source/Core/Core/GeckoCode.h index fffb83303c..fe8b391874 100644 --- a/Source/Core/Core/GeckoCode.h +++ b/Source/Core/Core/GeckoCode.h @@ -11,6 +11,11 @@ class PointerWrap; +namespace Core +{ +class CPUThreadGuard; +}; + namespace Gecko { class GeckoCode @@ -63,7 +68,7 @@ void SetActiveCodes(std::span gcodes); void SetSyncedCodesAsActive(); void UpdateSyncedCodes(std::span gcodes); std::vector SetAndReturnActiveCodes(std::span gcodes); -void RunCodeHandler(); +void RunCodeHandler(const Core::CPUThreadGuard& guard); void Shutdown(); void DoState(PointerWrap&); diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 301981b0c7..02a063fc6a 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -152,12 +152,12 @@ void Reload(Core::System& system) PatchFunctions(system); } -void Execute(u32 current_pc, u32 hook_index) +void Execute(const Core::CPUThreadGuard& guard, u32 current_pc, u32 hook_index) { hook_index &= 0xFFFFF; if (hook_index > 0 && hook_index < os_patches.size()) { - os_patches[hook_index].function(); + os_patches[hook_index].function(guard); } else { diff --git a/Source/Core/Core/HLE/HLE.h b/Source/Core/Core/HLE/HLE.h index 53d2b98d07..b51c3865c0 100644 --- a/Source/Core/Core/HLE/HLE.h +++ b/Source/Core/Core/HLE/HLE.h @@ -9,12 +9,13 @@ namespace Core { +class CPUThreadGuard; class System; -} +} // namespace Core namespace HLE { -using HookFunction = void (*)(); +using HookFunction = void (*)(const Core::CPUThreadGuard&); enum class HookType { @@ -46,7 +47,7 @@ void Reload(Core::System& system); void Patch(Core::System& system, u32 pc, std::string_view func_name); u32 UnPatch(Core::System& system, std::string_view patch_name); u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr); -void Execute(u32 current_pc, u32 hook_index); +void Execute(const Core::CPUThreadGuard& guard, u32 current_pc, u32 hook_index); // Returns the HLE hook index of the address u32 GetHookByAddress(u32 address); diff --git a/Source/Core/Core/HLE/HLE_Misc.cpp b/Source/Core/Core/HLE/HLE_Misc.cpp index 09152a1393..8ae8c0f747 100644 --- a/Source/Core/Core/HLE/HLE_Misc.cpp +++ b/Source/Core/Core/HLE/HLE_Misc.cpp @@ -16,21 +16,21 @@ namespace HLE_Misc { // If you just want to kill a function, one of the three following are usually appropriate. // According to the PPC ABI, the return value is always in r3. -void UnimplementedFunction() +void UnimplementedFunction(const Core::CPUThreadGuard&) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); ppc_state.npc = LR(ppc_state); } -void HBReload() +void HBReload(const Core::CPUThreadGuard&) { // There isn't much we can do. Just stop cleanly. CPU::Break(); Host_Message(HostMessageID::WMUserStop); } -void GeckoCodeHandlerICacheFlush() +void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); @@ -41,7 +41,7 @@ void GeckoCodeHandlerICacheFlush() // been read into memory, or such, so we do the first 5 frames. More // robust alternative would be to actually detect memory writes, but that // would be even uglier.) - u32 gch_gameid = PowerPC::HostRead_U32(Gecko::INSTALLER_BASE_ADDRESS); + u32 gch_gameid = PowerPC::HostRead_U32(guard, Gecko::INSTALLER_BASE_ADDRESS); if (gch_gameid - Gecko::MAGIC_GAMEID == 5) { return; @@ -50,7 +50,7 @@ void GeckoCodeHandlerICacheFlush() { gch_gameid = Gecko::MAGIC_GAMEID; } - PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS); + PowerPC::HostWrite_U32(guard, gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS); ppc_state.iCache.Reset(); } @@ -59,21 +59,21 @@ void GeckoCodeHandlerICacheFlush() // need a way to branch into the GCH from an arbitrary PC address. Branching is easy, returning // back is the hard part. This HLE function acts as a trampoline that restores the original LR, SP, // and PC before the magic, invisible BL instruction happened. -void GeckoReturnTrampoline() +void GeckoReturnTrampoline(const Core::CPUThreadGuard& guard) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); // Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler. u32 SP = ppc_state.gpr[1]; - ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8); - ppc_state.npc = PowerPC::HostRead_U32(SP + 12); - LR(ppc_state) = PowerPC::HostRead_U32(SP + 16); - ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20)); + ppc_state.gpr[1] = PowerPC::HostRead_U32(guard, SP + 8); + ppc_state.npc = PowerPC::HostRead_U32(guard, SP + 12); + LR(ppc_state) = PowerPC::HostRead_U32(guard, SP + 16); + ppc_state.cr.Set(PowerPC::HostRead_U32(guard, SP + 20)); for (int i = 0; i < 14; ++i) { - ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)), - PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64))); + ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(guard, SP + 24 + 2 * i * sizeof(u64)), + PowerPC::HostRead_U64(guard, SP + 24 + (2 * i + 1) * sizeof(u64))); } } } // namespace HLE_Misc diff --git a/Source/Core/Core/HLE/HLE_Misc.h b/Source/Core/Core/HLE/HLE_Misc.h index edbb33c530..68e8a74632 100644 --- a/Source/Core/Core/HLE/HLE_Misc.h +++ b/Source/Core/Core/HLE/HLE_Misc.h @@ -3,10 +3,15 @@ #pragma once +namespace Core +{ +class CPUThreadGuard; +}; + namespace HLE_Misc { -void UnimplementedFunction(); -void HBReload(); -void GeckoCodeHandlerICacheFlush(); -void GeckoReturnTrampoline(); +void UnimplementedFunction(const Core::CPUThreadGuard& guard); +void HBReload(const Core::CPUThreadGuard& guard); +void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard); +void GeckoReturnTrampoline(const Core::CPUThreadGuard& guard); } // namespace HLE_Misc diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 5383c820a0..7630b42430 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -23,19 +23,19 @@ enum class ParameterType : bool VariableArgumentList = true }; -std::string GetStringVA(Core::System& system, u32 str_reg = 3, +std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg = 3, ParameterType parameter_type = ParameterType::ParameterList); -void HLE_GeneralDebugPrint(ParameterType parameter_type); -void HLE_LogDPrint(ParameterType parameter_type); -void HLE_LogFPrint(ParameterType parameter_type); +void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type); +void HLE_LogDPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type); +void HLE_LogFPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type); -void HLE_OSPanic() +void HLE_OSPanic(const Core::CPUThreadGuard& guard) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); - std::string error = GetStringVA(system); - std::string msg = GetStringVA(system, 5); + std::string error = GetStringVA(system, guard); + std::string msg = GetStringVA(system, guard, 5); StringPopBackIf(&error, '\n'); StringPopBackIf(&msg, '\n'); @@ -48,7 +48,7 @@ void HLE_OSPanic() } // Generalized function for printing formatted string. -void HLE_GeneralDebugPrint(ParameterType parameter_type) +void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); @@ -56,32 +56,32 @@ void HLE_GeneralDebugPrint(ParameterType parameter_type) std::string report_message; // Is gpr3 pointing to a pointer (including nullptr) rather than an ASCII string - if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) && - (PowerPC::HostIsRAMAddress(PowerPC::HostRead_U32(ppc_state.gpr[3])) || - PowerPC::HostRead_U32(ppc_state.gpr[3]) == 0)) + if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3]) && + (PowerPC::HostIsRAMAddress(guard, PowerPC::HostRead_U32(guard, ppc_state.gpr[3])) || + PowerPC::HostRead_U32(guard, ppc_state.gpr[3]) == 0)) { - if (PowerPC::HostIsRAMAddress(ppc_state.gpr[4])) + if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[4])) { // ___blank(void* this, const char* fmt, ...); - report_message = GetStringVA(system, 4, parameter_type); + report_message = GetStringVA(system, guard, 4, parameter_type); } else { // ___blank(void* this, int log_type, const char* fmt, ...); - report_message = GetStringVA(system, 5, parameter_type); + report_message = GetStringVA(system, guard, 5, parameter_type); } } else { - if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3])) + if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3])) { // ___blank(const char* fmt, ...); - report_message = GetStringVA(system, 3, parameter_type); + report_message = GetStringVA(system, guard, 3, parameter_type); } else { // ___blank(int log_type, const char* fmt, ...); - report_message = GetStringVA(system, 4, parameter_type); + report_message = GetStringVA(system, guard, 4, parameter_type); } } @@ -92,25 +92,25 @@ void HLE_GeneralDebugPrint(ParameterType parameter_type) } // Generalized function for printing formatted string using parameter list. -void HLE_GeneralDebugPrint() +void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard) { - HLE_GeneralDebugPrint(ParameterType::ParameterList); + HLE_GeneralDebugPrint(guard, ParameterType::ParameterList); } // Generalized function for printing formatted string using va_list. -void HLE_GeneralDebugVPrint() +void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard) { - HLE_GeneralDebugPrint(ParameterType::VariableArgumentList); + HLE_GeneralDebugPrint(guard, ParameterType::VariableArgumentList); } // __write_console(int fd, const void* buffer, const u32* size) -void HLE_write_console() +void HLE_write_console(const Core::CPUThreadGuard& guard) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); - std::string report_message = GetStringVA(system, 4); - if (PowerPC::HostIsRAMAddress(ppc_state.gpr[5])) + std::string report_message = GetStringVA(system, guard, 4); + if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[5])) { const u32 size = PowerPC::Read_U32(ppc_state.gpr[5]); if (size > report_message.size()) @@ -132,7 +132,7 @@ void HLE_write_console() } // Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr) -void HLE_LogDPrint(ParameterType parameter_type) +void HLE_LogDPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); @@ -140,7 +140,7 @@ void HLE_LogDPrint(ParameterType parameter_type) if (ppc_state.gpr[3] != 1 && ppc_state.gpr[3] != 2) return; - std::string report_message = GetStringVA(system, 4, parameter_type); + std::string report_message = GetStringVA(system, guard, 4, parameter_type); StringPopBackIf(&report_message, '\n'); NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc, SHIFTJISToUTF8(report_message)); @@ -148,20 +148,20 @@ void HLE_LogDPrint(ParameterType parameter_type) // Log dprintf message // -> int dprintf(int fd, const char* format, ...); -void HLE_LogDPrint() +void HLE_LogDPrint(const Core::CPUThreadGuard& guard) { - HLE_LogDPrint(ParameterType::ParameterList); + HLE_LogDPrint(guard, ParameterType::ParameterList); } // Log vdprintf message // -> int vdprintf(int fd, const char* format, va_list ap); -void HLE_LogVDPrint() +void HLE_LogVDPrint(const Core::CPUThreadGuard& guard) { - HLE_LogDPrint(ParameterType::VariableArgumentList); + HLE_LogDPrint(guard, ParameterType::VariableArgumentList); } // Log (v)fprintf message if FILE is stdout or stderr -void HLE_LogFPrint(ParameterType parameter_type) +void HLE_LogFPrint(const Core::CPUThreadGuard& guard, ParameterType parameter_type) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); @@ -169,21 +169,21 @@ void HLE_LogFPrint(ParameterType parameter_type) // The structure FILE is implementation defined. // Both libogc and Dolphin SDK seem to store the fd at the same address. int fd = -1; - if (PowerPC::HostIsRAMAddress(ppc_state.gpr[3]) && - PowerPC::HostIsRAMAddress(ppc_state.gpr[3] + 0xF)) + if (PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3]) && + PowerPC::HostIsRAMAddress(guard, ppc_state.gpr[3] + 0xF)) { // The fd is stored as a short at FILE+0xE. - fd = static_cast(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0xE)); + fd = static_cast(PowerPC::HostRead_U16(guard, ppc_state.gpr[3] + 0xE)); } if (fd != 1 && fd != 2) { // On RVL SDK it seems stored at FILE+0x2. - fd = static_cast(PowerPC::HostRead_U16(ppc_state.gpr[3] + 0x2)); + fd = static_cast(PowerPC::HostRead_U16(guard, ppc_state.gpr[3] + 0x2)); } if (fd != 1 && fd != 2) return; - std::string report_message = GetStringVA(system, 4, parameter_type); + std::string report_message = GetStringVA(system, guard, 4, parameter_type); StringPopBackIf(&report_message, '\n'); NOTICE_LOG_FMT(OSREPORT_HLE, "{:08x}->{:08x}| {}", LR(ppc_state), ppc_state.pc, SHIFTJISToUTF8(report_message)); @@ -191,28 +191,30 @@ void HLE_LogFPrint(ParameterType parameter_type) // Log fprintf message // -> int fprintf(FILE* stream, const char* format, ...); -void HLE_LogFPrint() +void HLE_LogFPrint(const Core::CPUThreadGuard& guard) { - HLE_LogFPrint(ParameterType::ParameterList); + HLE_LogFPrint(guard, ParameterType::ParameterList); } // Log vfprintf message // -> int vfprintf(FILE* stream, const char* format, va_list ap); -void HLE_LogVFPrint() +void HLE_LogVFPrint(const Core::CPUThreadGuard& guard) { - HLE_LogFPrint(ParameterType::VariableArgumentList); + HLE_LogFPrint(guard, ParameterType::VariableArgumentList); } -std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType parameter_type) +std::string GetStringVA(Core::System& system, const Core::CPUThreadGuard& guard, u32 str_reg, + ParameterType parameter_type) { auto& ppc_state = system.GetPPCState(); std::string ArgumentBuffer; std::string result; - std::string string = PowerPC::HostGetString(ppc_state.gpr[str_reg]); + std::string string = PowerPC::HostGetString(guard, ppc_state.gpr[str_reg]); auto ap = parameter_type == ParameterType::VariableArgumentList ? - std::make_unique(system, ppc_state.gpr[str_reg + 1]) : + std::make_unique(system, guard, + ppc_state.gpr[str_reg + 1]) : std::make_unique(system, ppc_state.gpr[1] + 0x8, str_reg + 1); for (size_t i = 0; i < string.size(); i++) @@ -241,7 +243,7 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet { case 's': result += StringFromFormat(ArgumentBuffer.c_str(), - PowerPC::HostGetString(ap->GetArgT()).c_str()); + PowerPC::HostGetString(guard, ap->GetArgT(guard)).c_str()); break; case 'a': @@ -252,12 +254,12 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet case 'F': case 'g': case 'G': - result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT(guard)); break; case 'p': // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) - result += StringFromFormat("%x", ap->GetArgT()); + result += StringFromFormat("%x", ap->GetArgT(guard)); break; case 'n': @@ -267,9 +269,9 @@ std::string GetStringVA(Core::System& system, u32 str_reg, ParameterType paramet default: if (string[i - 1] == 'l' && string[i - 2] == 'l') - result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT(guard)); else - result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT(guard)); break; } } diff --git a/Source/Core/Core/HLE/HLE_OS.h b/Source/Core/Core/HLE/HLE_OS.h index e706c98082..6e13110b9b 100644 --- a/Source/Core/Core/HLE/HLE_OS.h +++ b/Source/Core/Core/HLE/HLE_OS.h @@ -3,14 +3,19 @@ #pragma once +namespace Core +{ +class CPUThreadGuard; +}; + namespace HLE_OS { -void HLE_GeneralDebugPrint(); -void HLE_GeneralDebugVPrint(); -void HLE_write_console(); -void HLE_OSPanic(); -void HLE_LogDPrint(); -void HLE_LogVDPrint(); -void HLE_LogFPrint(); -void HLE_LogVFPrint(); +void HLE_GeneralDebugPrint(const Core::CPUThreadGuard& guard); +void HLE_GeneralDebugVPrint(const Core::CPUThreadGuard& guard); +void HLE_write_console(const Core::CPUThreadGuard& guard); +void HLE_OSPanic(const Core::CPUThreadGuard& guard); +void HLE_LogDPrint(const Core::CPUThreadGuard& guard); +void HLE_LogVDPrint(const Core::CPUThreadGuard& guard); +void HLE_LogFPrint(const Core::CPUThreadGuard& guard); +void HLE_LogVFPrint(const Core::CPUThreadGuard& guard); } // namespace HLE_OS diff --git a/Source/Core/Core/HLE/HLE_VarArgs.cpp b/Source/Core/Core/HLE/HLE_VarArgs.cpp index 00d9f29df9..0e7e65561b 100644 --- a/Source/Core/Core/HLE/HLE_VarArgs.cpp +++ b/Source/Core/Core/HLE/HLE_VarArgs.cpp @@ -8,20 +8,22 @@ HLE::SystemVABI::VAList::~VAList() = default; -u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const +u32 HLE::SystemVABI::VAList::GetGPR(const Core::CPUThreadGuard&, u32 gpr) const { return m_system.GetPPCState().gpr[gpr]; } -double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const +double HLE::SystemVABI::VAList::GetFPR(const Core::CPUThreadGuard&, u32 fpr) const { return m_system.GetPPCState().ps[fpr].PS0AsDouble(); } -HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, u32 address) - : VAList(system, 0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1), - PowerPC::HostRead_U32(address + 4), - PowerPC::HostRead_U32(address + 8)}, +HLE::SystemVABI::VAListStruct::VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard, + u32 address) + : VAList(system, 0), m_va_list{PowerPC::HostRead_U8(guard, address), + PowerPC::HostRead_U8(guard, address + 1), + PowerPC::HostRead_U32(guard, address + 4), + PowerPC::HostRead_U32(guard, address + 8)}, m_address(address), m_has_fpr_area(system.GetPPCState().cr.GetBit(6) == 1) { m_stack = m_va_list.overflow_arg_area; @@ -39,7 +41,7 @@ u32 HLE::SystemVABI::VAListStruct::GetFPRArea() const return GetGPRArea() + 4 * 8; } -u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const +u32 HLE::SystemVABI::VAListStruct::GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const { if (gpr < 3 || gpr > 10) { @@ -47,10 +49,10 @@ u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const return 0; } const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4); - return PowerPC::HostRead_U32(gpr_address); + return PowerPC::HostRead_U32(guard, gpr_address); } -double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const +double HLE::SystemVABI::VAListStruct::GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const { if (!m_has_fpr_area || fpr < 1 || fpr > 8) { @@ -58,5 +60,5 @@ double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const return 0.0; } const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8); - return PowerPC::HostRead_F64(fpr_address); + return PowerPC::HostRead_F64(guard, fpr_address); } diff --git a/Source/Core/Core/HLE/HLE_VarArgs.h b/Source/Core/Core/HLE/HLE_VarArgs.h index 0ef47a5e3a..6ed4919a69 100644 --- a/Source/Core/Core/HLE/HLE_VarArgs.h +++ b/Source/Core/Core/HLE/HLE_VarArgs.h @@ -13,8 +13,9 @@ namespace Core { +class CPUThreadGuard; class System; -} +} // namespace Core namespace HLE::SystemVABI { @@ -47,14 +48,14 @@ public: // 0 - arg_ARGPOINTER template >* = nullptr> - T GetArg() + T GetArg(const Core::CPUThreadGuard& guard) { T obj; - u32 addr = GetArg(); + u32 addr = GetArg(guard); for (size_t i = 0; i < sizeof(T); i += 1, addr += 1) { - reinterpret_cast(&obj)[i] = PowerPC::HostRead_U8(addr); + reinterpret_cast(&obj)[i] = PowerPC::HostRead_U8(guard, addr); } return obj; @@ -62,20 +63,20 @@ public: // 1 - arg_WORD template >* = nullptr> - T GetArg() + T GetArg(const Core::CPUThreadGuard& guard) { static_assert(!std::is_pointer(), "VAList doesn't support pointers"); u64 value; if (m_gpr <= m_gpr_max) { - value = GetGPR(m_gpr); + value = GetGPR(guard, m_gpr); m_gpr += 1; } else { m_stack = Common::AlignUp(m_stack, 4); - value = PowerPC::HostRead_U32(m_stack); + value = PowerPC::HostRead_U32(guard, m_stack); m_stack += 4; } @@ -84,7 +85,7 @@ public: // 2 - arg_DOUBLEWORD template >* = nullptr> - T GetArg() + T GetArg(const Core::CPUThreadGuard& guard) { u64 value; @@ -92,13 +93,13 @@ public: m_gpr += 1; if (m_gpr < m_gpr_max) { - value = static_cast(GetGPR(m_gpr)) << 32 | GetGPR(m_gpr + 1); + value = static_cast(GetGPR(guard, m_gpr)) << 32 | GetGPR(guard, m_gpr + 1); m_gpr += 2; } else { m_stack = Common::AlignUp(m_stack, 8); - value = PowerPC::HostRead_U64(m_stack); + value = PowerPC::HostRead_U64(guard, m_stack); m_stack += 8; } @@ -107,19 +108,19 @@ public: // 3 - arg_ARGREAL template >* = nullptr> - T GetArg() + T GetArg(const Core::CPUThreadGuard& guard) { double value; if (m_fpr <= m_fpr_max) { - value = GetFPR(m_fpr); + value = GetFPR(guard, m_fpr); m_fpr += 1; } else { m_stack = Common::AlignUp(m_stack, 8); - value = PowerPC::HostRead_F64(m_stack); + value = PowerPC::HostRead_F64(guard, m_stack); m_stack += 8; } @@ -128,9 +129,9 @@ public: // Helper template - T GetArgT() + T GetArgT(const Core::CPUThreadGuard& guard) { - return static_cast(GetArg()); + return static_cast(GetArg(guard)); } protected: @@ -142,8 +143,8 @@ protected: u32 m_stack; private: - virtual u32 GetGPR(u32 gpr) const; - virtual double GetFPR(u32 fpr) const; + virtual u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const; + virtual double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const; }; // See System V ABI (SVR4) for more details @@ -155,7 +156,7 @@ private: class VAListStruct : public VAList { public: - explicit VAListStruct(Core::System& system, u32 address); + explicit VAListStruct(Core::System& system, const Core::CPUThreadGuard& guard, u32 address); ~VAListStruct() = default; private: @@ -173,8 +174,8 @@ private: u32 GetGPRArea() const; u32 GetFPRArea() const; - u32 GetGPR(u32 gpr) const override; - double GetFPR(u32 fpr) const override; + u32 GetGPR(const Core::CPUThreadGuard& guard, u32 gpr) const override; + double GetFPR(const Core::CPUThreadGuard& guard, u32 fpr) const override; }; } // namespace HLE::SystemVABI diff --git a/Source/Core/Core/HW/AddressSpace.cpp b/Source/Core/Core/HW/AddressSpace.cpp index 1e0a1608a5..9a884cd53b 100644 --- a/Source/Core/Core/HW/AddressSpace.cpp +++ b/Source/Core/Core/HW/AddressSpace.cpp @@ -14,48 +14,48 @@ namespace AddressSpace { -u16 Accessors::ReadU16(u32 address) const +u16 Accessors::ReadU16(const Core::CPUThreadGuard& guard, u32 address) const { - u32 result = ReadU8(address); - result = result << 8 | ReadU8(address + 1); + u32 result = ReadU8(guard, address); + result = result << 8 | ReadU8(guard, address + 1); return result; } -void Accessors::WriteU16(u32 address, u16 value) +void Accessors::WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value) { - WriteU8(address, value & 0xff); - WriteU8(address + 1, (value >> 8) & 0xff); + WriteU8(guard, address, value & 0xff); + WriteU8(guard, address + 1, (value >> 8) & 0xff); } -u32 Accessors::ReadU32(u32 address) const +u32 Accessors::ReadU32(const Core::CPUThreadGuard& guard, u32 address) const { - u32 result = ReadU16(address); - result = result << 16 | ReadU16(address + 2); + u32 result = ReadU16(guard, address); + result = result << 16 | ReadU16(guard, address + 2); return result; } -void Accessors::WriteU32(u32 address, u32 value) +void Accessors::WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value) { - WriteU16(address, value & 0xffff); - WriteU16(address + 2, (value >> 16) & 0xffff); + WriteU16(guard, address, value & 0xffff); + WriteU16(guard, address + 2, (value >> 16) & 0xffff); } -u64 Accessors::ReadU64(u32 address) const +u64 Accessors::ReadU64(const Core::CPUThreadGuard& guard, u32 address) const { - u64 result = ReadU32(address); - result = result << 32 | ReadU32(address + 4); + u64 result = ReadU32(guard, address); + result = result << 32 | ReadU32(guard, address + 4); return result; } -void Accessors::WriteU64(u32 address, u64 value) +void Accessors::WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value) { - WriteU32(address, value & 0xffffffff); - WriteU32(address + 4, (value >> 32) & 0xffffffff); + WriteU32(guard, address, value & 0xffffffff); + WriteU32(guard, address + 4, (value >> 32) & 0xffffffff); } -float Accessors::ReadF32(u32 address) const +float Accessors::ReadF32(const Core::CPUThreadGuard& guard, u32 address) const { - return Common::BitCast(ReadU32(address)); + return Common::BitCast(ReadU32(guard, address)); } Accessors::iterator Accessors::begin() const @@ -68,8 +68,9 @@ Accessors::iterator Accessors::end() const return nullptr; } -std::optional Accessors::Search(u32 haystack_start, const u8* needle_start, - std::size_t needle_size, bool forwards) const +std::optional Accessors::Search(const Core::CPUThreadGuard& guard, u32 haystack_start, + const u8* needle_start, std::size_t needle_size, + bool forwards) const { return std::nullopt; } @@ -80,18 +81,49 @@ Accessors::~Accessors() struct EffectiveAddressSpaceAccessors : Accessors { - bool IsValidAddress(u32 address) const override { return PowerPC::HostIsRAMAddress(address); } - u8 ReadU8(u32 address) const override { return PowerPC::HostRead_U8(address); } - void WriteU8(u32 address, u8 value) override { PowerPC::HostWrite_U8(value, address); } - u16 ReadU16(u32 address) const override { return PowerPC::HostRead_U16(address); } - void WriteU16(u32 address, u16 value) override { PowerPC::HostWrite_U16(value, address); } - u32 ReadU32(u32 address) const override { return PowerPC::HostRead_U32(address); } - void WriteU32(u32 address, u32 value) override { PowerPC::HostWrite_U32(value, address); } - u64 ReadU64(u32 address) const override { return PowerPC::HostRead_U64(address); } - void WriteU64(u32 address, u64 value) override { PowerPC::HostWrite_U64(value, address); } - float ReadF32(u32 address) const override { return PowerPC::HostRead_F32(address); }; + bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostIsRAMAddress(guard, address); + } + u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostRead_U8(guard, address); + } + void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override + { + PowerPC::HostWrite_U8(guard, value, address); + } + u16 ReadU16(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostRead_U16(guard, address); + } + void WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value) override + { + PowerPC::HostWrite_U16(guard, value, address); + } + u32 ReadU32(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostRead_U32(guard, address); + } + void WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value) override + { + PowerPC::HostWrite_U32(guard, value, address); + } + u64 ReadU64(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostRead_U64(guard, address); + } + void WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value) override + { + PowerPC::HostWrite_U64(guard, value, address); + } + float ReadF32(const Core::CPUThreadGuard& guard, u32 address) const override + { + return PowerPC::HostRead_F32(guard, address); + }; - bool Matches(u32 haystack_start, const u8* needle_start, std::size_t needle_size) const + bool Matches(const Core::CPUThreadGuard& guard, u32 haystack_start, const u8* needle_start, + std::size_t needle_size) const { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); @@ -100,7 +132,7 @@ struct EffectiveAddressSpaceAccessors : Accessors u32 offset = haystack_start & 0x0000fff; do { - if (!PowerPC::HostIsRAMAddress(page_base)) + if (!PowerPC::HostIsRAMAddress(guard, page_base)) { return false; } @@ -137,7 +169,8 @@ struct EffectiveAddressSpaceAccessors : Accessors return (needle_size == 0); } - std::optional Search(u32 haystack_start, const u8* needle_start, std::size_t needle_size, + std::optional Search(const Core::CPUThreadGuard& guard, u32 haystack_start, + const u8* needle_start, std::size_t needle_size, bool forward) const override { u32 haystack_address = haystack_start; @@ -150,11 +183,11 @@ struct EffectiveAddressSpaceAccessors : Accessors const u32 haystack_offset_change = forward ? 1 : -1; do { - if (PowerPC::HostIsRAMAddress(haystack_address)) + if (PowerPC::HostIsRAMAddress(guard, haystack_address)) { do { - if (Matches(haystack_address, needle_start, needle_size)) + if (Matches(guard, haystack_address, needle_start, needle_size)) { return std::optional(haystack_address); } @@ -173,17 +206,17 @@ struct EffectiveAddressSpaceAccessors : Accessors struct AuxiliaryAddressSpaceAccessors : Accessors { static constexpr u32 aram_base_address = 0; - bool IsValidAddress(u32 address) const override + bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override { return !SConfig::GetInstance().bWii && (address - aram_base_address) < GetSize(); } - u8 ReadU8(u32 address) const override + u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override { const u8* base = DSP::GetARAMPtr(); return base[address]; } - void WriteU8(u32 address, u8 value) override + void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override { u8* base = DSP::GetARAMPtr(); base[address] = value; @@ -193,10 +226,11 @@ struct AuxiliaryAddressSpaceAccessors : Accessors iterator end() const override { return DSP::GetARAMPtr() + GetSize(); } - std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, + std::optional Search(const Core::CPUThreadGuard& guard, u32 haystack_offset, + const u8* needle_start, std::size_t needle_size, bool forward) const override { - if (!IsValidAddress(haystack_offset)) + if (!IsValidAddress(guard, haystack_offset)) { return std::nullopt; } @@ -243,42 +277,44 @@ struct CompositeAddressSpaceAccessors : Accessors { } - bool IsValidAddress(u32 address) const override + bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override { - return FindAppropriateAccessor(address) != m_accessor_mappings.end(); + return FindAppropriateAccessor(guard, address) != m_accessor_mappings.end(); } - u8 ReadU8(u32 address) const override + u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override { - auto mapping = FindAppropriateAccessor(address); + auto mapping = FindAppropriateAccessor(guard, address); if (mapping == m_accessor_mappings.end()) { return 0; } - return mapping->accessors->ReadU8(address - mapping->base); + return mapping->accessors->ReadU8(guard, address - mapping->base); } - void WriteU8(u32 address, u8 value) override + void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override { - auto mapping = FindAppropriateAccessor(address); + auto mapping = FindAppropriateAccessor(guard, address); if (mapping == m_accessor_mappings.end()) { return; } - return mapping->accessors->WriteU8(address - mapping->base, value); + return mapping->accessors->WriteU8(guard, address - mapping->base, value); } - std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, + std::optional Search(const Core::CPUThreadGuard& guard, u32 haystack_offset, + const u8* needle_start, std::size_t needle_size, bool forward) const override { for (const AccessorMapping& mapping : m_accessor_mappings) { u32 mapping_offset = haystack_offset - mapping.base; - if (!mapping.accessors->IsValidAddress(mapping_offset)) + if (!mapping.accessors->IsValidAddress(guard, mapping_offset)) { continue; } - auto result = mapping.accessors->Search(mapping_offset, needle_start, needle_size, forward); + auto result = + mapping.accessors->Search(guard, mapping_offset, needle_start, needle_size, forward); if (result.has_value()) { return std::optional(*result + mapping.base); @@ -289,18 +325,20 @@ struct CompositeAddressSpaceAccessors : Accessors private: std::vector m_accessor_mappings; - std::vector::iterator FindAppropriateAccessor(u32 address) + std::vector::iterator FindAppropriateAccessor(const Core::CPUThreadGuard& guard, + u32 address) { return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(), - [address](const AccessorMapping& a) { - return a.accessors->IsValidAddress(address - a.base); + [&guard, address](const AccessorMapping& a) { + return a.accessors->IsValidAddress(guard, address - a.base); }); } - std::vector::const_iterator FindAppropriateAccessor(u32 address) const + std::vector::const_iterator + FindAppropriateAccessor(const Core::CPUThreadGuard& guard, u32 address) const { return std::find_if(m_accessor_mappings.begin(), m_accessor_mappings.end(), - [address](const AccessorMapping& a) { - return a.accessors->IsValidAddress(address - a.base); + [&guard, address](const AccessorMapping& a) { + return a.accessors->IsValidAddress(guard, address - a.base); }); } }; @@ -310,13 +348,19 @@ struct SmallBlockAccessors : Accessors SmallBlockAccessors() = default; SmallBlockAccessors(u8** alloc_base_, u32 size_) : alloc_base{alloc_base_}, size{size_} {} - bool IsValidAddress(u32 address) const override + bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override { return (*alloc_base != nullptr) && (address < size); } - u8 ReadU8(u32 address) const override { return (*alloc_base)[address]; } + u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override + { + return (*alloc_base)[address]; + } - void WriteU8(u32 address, u8 value) override { (*alloc_base)[address] = value; } + void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override + { + (*alloc_base)[address] = value; + } iterator begin() const override { return *alloc_base; } @@ -325,11 +369,12 @@ struct SmallBlockAccessors : Accessors return (*alloc_base == nullptr) ? nullptr : (*alloc_base + size); } - std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, + std::optional Search(const Core::CPUThreadGuard& guard, u32 haystack_offset, + const u8* needle_start, std::size_t needle_size, bool forward) const override { - if (!IsValidAddress(haystack_offset) || - !IsValidAddress(haystack_offset + static_cast(needle_size) - 1)) + if (!IsValidAddress(guard, haystack_offset) || + !IsValidAddress(guard, haystack_offset + static_cast(needle_size) - 1)) { return std::nullopt; } @@ -364,9 +409,12 @@ private: struct NullAccessors : Accessors { - bool IsValidAddress(u32 address) const override { return false; } - u8 ReadU8(u32 address) const override { return 0; } - void WriteU8(u32 address, u8 value) override {} + bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const override + { + return false; + } + u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const override { return 0; } + void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) override {} }; static EffectiveAddressSpaceAccessors s_effective_address_space_accessors; diff --git a/Source/Core/Core/HW/AddressSpace.h b/Source/Core/Core/HW/AddressSpace.h index f70f125101..63302999fe 100644 --- a/Source/Core/Core/HW/AddressSpace.h +++ b/Source/Core/Core/HW/AddressSpace.h @@ -7,6 +7,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +} + namespace AddressSpace { enum class Type @@ -23,24 +28,25 @@ struct Accessors { using iterator = const u8*; - virtual bool IsValidAddress(u32 address) const = 0; - virtual u8 ReadU8(u32 address) const = 0; - virtual void WriteU8(u32 address, u8 value) = 0; + virtual bool IsValidAddress(const Core::CPUThreadGuard& guard, u32 address) const = 0; + virtual u8 ReadU8(const Core::CPUThreadGuard& guard, u32 address) const = 0; + virtual void WriteU8(const Core::CPUThreadGuard& guard, u32 address, u8 value) = 0; // overrideable naive implementations of below are defined - virtual u16 ReadU16(u32 address) const; - virtual void WriteU16(u32 address, u16 value); - virtual u32 ReadU32(u32 address) const; - virtual void WriteU32(u32 address, u32 value); - virtual u64 ReadU64(u32 address) const; - virtual void WriteU64(u32 address, u64 value); - virtual float ReadF32(u32 address) const; + virtual u16 ReadU16(const Core::CPUThreadGuard& guard, u32 address) const; + virtual void WriteU16(const Core::CPUThreadGuard& guard, u32 address, u16 value); + virtual u32 ReadU32(const Core::CPUThreadGuard& guard, u32 address) const; + virtual void WriteU32(const Core::CPUThreadGuard& guard, u32 address, u32 value); + virtual u64 ReadU64(const Core::CPUThreadGuard& guard, u32 address) const; + virtual void WriteU64(const Core::CPUThreadGuard& guard, u32 address, u64 value); + virtual float ReadF32(const Core::CPUThreadGuard& guard, u32 address) const; virtual iterator begin() const; virtual iterator end() const; - virtual std::optional Search(u32 haystack_offset, const u8* needle_start, - std::size_t needle_size, bool forward) const; + virtual std::optional Search(const Core::CPUThreadGuard& guard, u32 haystack_offset, + const u8* needle_start, std::size_t needle_size, + bool forward) const; virtual ~Accessors(); }; diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index cfe5faa607..83851ed4f3 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -17,6 +17,7 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Timer.h" + #include "Core/Boot/AncastTypes.h" #include "Core/Boot/DolReader.h" #include "Core/Boot/ElfReader.h" @@ -912,7 +913,10 @@ static void FinishPPCBootstrap(Core::System& system, u64 userdata, s64 cycles_la else ReleasePPC(); - SConfig::OnNewTitleLoad(); + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + SConfig::OnNewTitleLoad(guard); + INFO_LOG_FMT(IOS, "Bootstrapping done."); } diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index f1062b2f0b..d4820e2c43 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -6,11 +6,13 @@ #include #include +#include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/Swap.h" + #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -57,6 +59,10 @@ bool Load() { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); + + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); memory.Write_U32(0x09142001, 0x3180); @@ -69,7 +75,7 @@ bool Load() g_symbolDB.Clear(); Host_NotifyMapLoaded(); } - if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) + if (g_symbolDB.LoadMap(guard, File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) { ::HLE::Clear(); ::HLE::PatchFunctions(system); @@ -93,7 +99,7 @@ bool Load() NOTICE_LOG_FMT(IOS, "IPL ready."); SConfig::GetInstance().m_is_mios = true; DVDInterface::UpdateRunningGameMetadata(); - SConfig::OnNewTitleLoad(); + SConfig::OnNewTitleLoad(guard); return true; } } // namespace IOS::HLE::MIOS diff --git a/Source/Core/Core/MemoryWatcher.cpp b/Source/Core/Core/MemoryWatcher.cpp index ec30fa6d82..f2456f6d57 100644 --- a/Source/Core/Core/MemoryWatcher.cpp +++ b/Source/Core/Core/MemoryWatcher.cpp @@ -67,19 +67,19 @@ bool MemoryWatcher::OpenSocket(const std::string& path) return m_fd >= 0; } -u32 MemoryWatcher::ChasePointer(const std::string& line) +u32 MemoryWatcher::ChasePointer(const Core::CPUThreadGuard& guard, const std::string& line) { u32 value = 0; for (u32 offset : m_addresses[line]) { - value = PowerPC::HostRead_U32(value + offset); - if (!PowerPC::HostIsRAMAddress(value)) + value = PowerPC::HostRead_U32(guard, value + offset); + if (!PowerPC::HostIsRAMAddress(guard, value)) break; } return value; } -std::string MemoryWatcher::ComposeMessages() +std::string MemoryWatcher::ComposeMessages(const Core::CPUThreadGuard& guard) { std::ostringstream message_stream; message_stream << std::hex; @@ -89,7 +89,7 @@ std::string MemoryWatcher::ComposeMessages() std::string address = entry.first; u32& current_value = entry.second; - u32 new_value = ChasePointer(address); + u32 new_value = ChasePointer(guard, address); if (new_value != current_value) { // Update the value @@ -101,12 +101,12 @@ std::string MemoryWatcher::ComposeMessages() return message_stream.str(); } -void MemoryWatcher::Step() +void MemoryWatcher::Step(const Core::CPUThreadGuard& guard) { if (!m_running) return; - std::string message = ComposeMessages(); + std::string message = ComposeMessages(guard); sendto(m_fd, message.c_str(), message.size() + 1, 0, reinterpret_cast(&m_addr), sizeof(m_addr)); } diff --git a/Source/Core/Core/MemoryWatcher.h b/Source/Core/Core/MemoryWatcher.h index 3887d68e35..d4134f6ed8 100644 --- a/Source/Core/Core/MemoryWatcher.h +++ b/Source/Core/Core/MemoryWatcher.h @@ -11,6 +11,11 @@ #include #include +namespace Core +{ +class CPUThreadGuard; +} + // MemoryWatcher reads a file containing in-game memory addresses and outputs // changes to those memory addresses to a unix domain socket as the game runs. // @@ -24,15 +29,15 @@ class MemoryWatcher final public: MemoryWatcher(); ~MemoryWatcher(); - void Step(); + void Step(const Core::CPUThreadGuard& guard); private: bool LoadAddresses(const std::string& path); bool OpenSocket(const std::string& path); void ParseLine(const std::string& line); - u32 ChasePointer(const std::string& line); - std::string ComposeMessages(); + u32 ChasePointer(const Core::CPUThreadGuard& guard, const std::string& line); + std::string ComposeMessages(const Core::CPUThreadGuard& guard); bool m_running = false; diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index 0b07a604fd..0d736503a3 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -28,6 +28,7 @@ #include "Core/CheatCodes.h" #include "Core/Config/SessionSettings.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/Debugger/PPCDebugInterface.h" #include "Core/GeckoCode.h" #include "Core/GeckoCodeConfig.h" @@ -230,7 +231,7 @@ void LoadPatches() LoadSpeedhacks("Speedhacks", merged); } -static void ApplyPatches(const std::vector& patches) +static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector& patches) { for (const Patch& patch : patches) { @@ -244,16 +245,17 @@ static void ApplyPatches(const std::vector& patches) switch (entry.type) { case PatchType::Patch8Bit: - if (!entry.conditional || PowerPC::HostRead_U8(addr) == static_cast(comparand)) - PowerPC::HostWrite_U8(static_cast(value), addr); + if (!entry.conditional || PowerPC::HostRead_U8(guard, addr) == static_cast(comparand)) + PowerPC::HostWrite_U8(guard, static_cast(value), addr); break; case PatchType::Patch16Bit: - if (!entry.conditional || PowerPC::HostRead_U16(addr) == static_cast(comparand)) - PowerPC::HostWrite_U16(static_cast(value), addr); + if (!entry.conditional || + PowerPC::HostRead_U16(guard, addr) == static_cast(comparand)) + PowerPC::HostWrite_U16(guard, static_cast(value), addr); break; case PatchType::Patch32Bit: - if (!entry.conditional || PowerPC::HostRead_U32(addr) == comparand) - PowerPC::HostWrite_U32(value, addr); + if (!entry.conditional || PowerPC::HostRead_U32(guard, addr) == comparand) + PowerPC::HostWrite_U32(guard, value, addr); break; default: // unknown patchtype @@ -264,19 +266,20 @@ static void ApplyPatches(const std::vector& patches) } } -static void ApplyMemoryPatches(std::span memory_patch_indices) +static void ApplyMemoryPatches(const Core::CPUThreadGuard& guard, + std::span memory_patch_indices) { std::lock_guard lock(s_on_frame_memory_mutex); for (std::size_t index : memory_patch_indices) { - PowerPC::debug_interface.ApplyExistingPatch(index); + PowerPC::debug_interface.ApplyExistingPatch(guard, index); } } // Requires MSR.DR, MSR.IR // There's no perfect way to do this, it's just a heuristic. // We require at least 2 stack frames, if the stack is shallower than that then it won't work. -static bool IsStackSane() +static bool IsStackValid(const Core::CPUThreadGuard& guard) { auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); @@ -285,19 +288,19 @@ static bool IsStackSane() // Check the stack pointer u32 SP = ppc_state.gpr[1]; - if (!PowerPC::HostIsRAMAddress(SP)) + if (!PowerPC::HostIsRAMAddress(guard, SP)) return false; // Read the frame pointer from the stack (find 2nd frame from top), assert that it makes sense - u32 next_SP = PowerPC::HostRead_U32(SP); - if (next_SP <= SP || !PowerPC::HostIsRAMAddress(next_SP) || - !PowerPC::HostIsRAMAddress(next_SP + 4)) + u32 next_SP = PowerPC::HostRead_U32(guard, SP); + if (next_SP <= SP || !PowerPC::HostIsRAMAddress(guard, next_SP) || + !PowerPC::HostIsRAMAddress(guard, next_SP + 4)) return false; // Check the link register makes sense (that it points to a valid IBAT address) - const u32 address = PowerPC::HostRead_U32(next_SP + 4); - return PowerPC::HostIsInstructionRAMAddress(address) && - 0 != PowerPC::HostRead_Instruction(address); + const u32 address = PowerPC::HostRead_U32(guard, next_SP + 4); + return PowerPC::HostIsInstructionRAMAddress(guard, address) && + 0 != PowerPC::HostRead_Instruction(guard, address); } void AddMemoryPatch(std::size_t index) @@ -318,11 +321,14 @@ bool ApplyFramePatches() auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + // Because we're using the VI Interrupt to time this instead of patching the game with a // callback hook we can end up catching the game in an exception vector. // We deal with this by returning false so that SystemTimers will reschedule us in a few cycles // where we can try again after the CPU hopefully returns back to the normal instruction flow. - if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackSane()) + if (!ppc_state.msr.DR || !ppc_state.msr.IR || !IsStackValid(guard)) { DEBUG_LOG_FMT(ACTIONREPLAY, "Need to retry later. CPU configuration is currently incorrect. PC = {:#010x}, " @@ -331,12 +337,12 @@ bool ApplyFramePatches() return false; } - ApplyPatches(s_on_frame); - ApplyMemoryPatches(s_on_frame_memory); + ApplyPatches(guard, s_on_frame); + ApplyMemoryPatches(guard, s_on_frame_memory); // Run the Gecko code handler - Gecko::RunCodeHandler(); - ActionReplay::RunAllActive(); + Gecko::RunCodeHandler(guard); + ActionReplay::RunAllActive(guard); return true; } diff --git a/Source/Core/Core/PowerPC/Expression.cpp b/Source/Core/Core/PowerPC/Expression.cpp index 67e8104c38..7966d75982 100644 --- a/Source/Core/Core/PowerPC/Expression.cpp +++ b/Source/Core/Core/PowerPC/Expression.cpp @@ -23,57 +23,57 @@ #include "Core/System.h" template -static T HostRead(u32 address); +static T HostRead(const Core::CPUThreadGuard& guard, u32 address); template -static void HostWrite(T var, u32 address); +static void HostWrite(const Core::CPUThreadGuard& guard, T var, u32 address); template <> -u8 HostRead(u32 address) +u8 HostRead(const Core::CPUThreadGuard& guard, u32 address) { - return PowerPC::HostRead_U8(address); + return PowerPC::HostRead_U8(guard, address); } template <> -u16 HostRead(u32 address) +u16 HostRead(const Core::CPUThreadGuard& guard, u32 address) { - return PowerPC::HostRead_U16(address); + return PowerPC::HostRead_U16(guard, address); } template <> -u32 HostRead(u32 address) +u32 HostRead(const Core::CPUThreadGuard& guard, u32 address) { - return PowerPC::HostRead_U32(address); + return PowerPC::HostRead_U32(guard, address); } template <> -u64 HostRead(u32 address) +u64 HostRead(const Core::CPUThreadGuard& guard, u32 address) { - return PowerPC::HostRead_U64(address); + return PowerPC::HostRead_U64(guard, address); } template <> -void HostWrite(u8 var, u32 address) +void HostWrite(const Core::CPUThreadGuard& guard, u8 var, u32 address) { - PowerPC::HostWrite_U8(var, address); + PowerPC::HostWrite_U8(guard, var, address); } template <> -void HostWrite(u16 var, u32 address) +void HostWrite(const Core::CPUThreadGuard& guard, u16 var, u32 address) { - PowerPC::HostWrite_U16(var, address); + PowerPC::HostWrite_U16(guard, var, address); } template <> -void HostWrite(u32 var, u32 address) +void HostWrite(const Core::CPUThreadGuard& guard, u32 var, u32 address) { - PowerPC::HostWrite_U32(var, address); + PowerPC::HostWrite_U32(guard, var, address); } template <> -void HostWrite(u64 var, u32 address) +void HostWrite(const Core::CPUThreadGuard& guard, u64 var, u32 address) { - PowerPC::HostWrite_U64(var, address); + PowerPC::HostWrite_U64(guard, var, address); } template @@ -81,8 +81,9 @@ static double HostReadFunc(expr_func* f, vec_expr_t* args, void* c) { if (vec_len(args) != 1) return 0; + const auto* guard = reinterpret_cast(c); const u32 address = static_cast(expr_eval(&vec_nth(args, 0))); - return Common::BitCast(HostRead(address)); + return Common::BitCast(HostRead(*guard, address)); } template @@ -90,9 +91,10 @@ static double HostWriteFunc(expr_func* f, vec_expr_t* args, void* c) { if (vec_len(args) != 2) return 0; + const auto* guard = reinterpret_cast(c); const T var = static_cast(expr_eval(&vec_nth(args, 0))); const u32 address = static_cast(expr_eval(&vec_nth(args, 1))); - HostWrite(Common::BitCast(var), address); + HostWrite(*guard, Common::BitCast(var), address); return var; } @@ -110,7 +112,8 @@ static double CallstackFunc(expr_func* f, vec_expr_t* args, void* c) return 0; std::vector stack; - bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack); + const auto* guard = reinterpret_cast(c); + bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), *guard, stack); if (!success) return 0; @@ -225,7 +228,13 @@ double Expression::Evaluate() const { SynchronizeBindings(SynchronizeDirection::From); - double result = expr_eval(m_expr.get()); + double result; + { + Core::CPUThreadGuard guard; + m_expr->param.func.context = &guard; + result = expr_eval(m_expr.get()); + m_expr->param.func.context = nullptr; + } SynchronizeBindings(SynchronizeDirection::To); diff --git a/Source/Core/Core/PowerPC/Expression.h b/Source/Core/Core/PowerPC/Expression.h index 7fb5370328..2c96e04f44 100644 --- a/Source/Core/Core/PowerPC/Expression.h +++ b/Source/Core/Core/PowerPC/Expression.h @@ -12,6 +12,11 @@ struct expr; struct expr_var_list; +namespace Core +{ +class CPUThreadGuard; +} + struct ExprDeleter { void operator()(expr* expression) const; diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 45ac436469..782fc32158 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -25,6 +25,7 @@ typedef SSIZE_T ssize_t; #include #endif +#include "Common/Assert.h" #include "Common/Event.h" #include "Common/Logging/Log.h" #include "Common/SocketContext.h" @@ -799,7 +800,7 @@ static void WriteRegister() SendReply("OK"); } -static void ReadMemory() +static void ReadMemory(const Core::CPUThreadGuard& guard) { static u8 reply[GDB_BFR_MAX - 4]; u32 addr, len; @@ -819,7 +820,7 @@ static void ReadMemory() if (len * 2 > sizeof reply) SendReply("E01"); - if (!PowerPC::HostIsRAMAddress(addr)) + if (!PowerPC::HostIsRAMAddress(guard, addr)) return SendReply("E00"); auto& system = Core::System::GetInstance(); @@ -830,7 +831,7 @@ static void ReadMemory() SendReply((char*)reply); } -static void WriteMemory() +static void WriteMemory(const Core::CPUThreadGuard& guard) { u32 addr, len; u32 i; @@ -846,7 +847,7 @@ static void WriteMemory() len = (len << 4) | Hex2char(s_cmd_bfr[i++]); INFO_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr); - if (!PowerPC::HostIsRAMAddress(addr)) + if (!PowerPC::HostIsRAMAddress(guard, addr)) return SendReply("E00"); auto& system = Core::System::GetInstance(); @@ -990,11 +991,19 @@ void ProcessCommands(bool loop_until_continue) WriteRegister(); break; case 'm': - ReadMemory(); + { + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + + ReadMemory(guard); break; + } case 'M': { - WriteMemory(); + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + + WriteMemory(guard); auto& system = Core::System::GetInstance(); auto& ppc_state = system.GetPPCState(); ppc_state.iCache.Reset(); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index d26aa2b700..f952733d96 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Core/Config/MainSettings.h" +#include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/HLE/HLE.h" @@ -339,11 +340,14 @@ void Interpreter::Run() void Interpreter::unknown_instruction(UGeckoInstruction inst) { - const u32 opcode = PowerPC::HostRead_U32(last_pc); + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + + const u32 opcode = PowerPC::HostRead_U32(guard, last_pc); const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc); NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm); - Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), Common::Log::LogType::POWERPC, - Common::Log::LogLevel::LNOTICE); + Dolphin_Debugger::PrintCallstack(Core::System::GetInstance(), guard, + Common::Log::LogType::POWERPC, Common::Log::LogLevel::LNOTICE); NOTICE_LOG_FMT( POWERPC, "\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n", diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp index 13c739b9f3..2a881301e0 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp @@ -6,6 +6,7 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/HLE/HLE.h" #include "Core/PowerPC/Interpreter/ExceptionUtils.h" #include "Core/PowerPC/PowerPC.h" @@ -95,7 +96,11 @@ void Interpreter::bclrx(UGeckoInstruction inst) void Interpreter::HLEFunction(UGeckoInstruction inst) { m_end_block = true; - HLE::Execute(PowerPC::ppcState.pc, inst.hex); + + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + + HLE::Execute(guard, PowerPC::ppcState.pc, inst.hex); } void Interpreter::rfi(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index 999cd43d81..5b1d7a1f9c 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -16,6 +16,7 @@ #include +#include "Common/Assert.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/IOFile.h" @@ -271,8 +272,12 @@ void CompileExceptionCheck(ExceptionType type) { if (type == ExceptionType::FIFOWrite) { + ASSERT(Core::IsCPUThread()); + Core::CPUThreadGuard guard; + // Check in case the code has been replaced since: do we need to do this? - const OpType optype = PPCTables::GetOpInfo(PowerPC::HostRead_U32(PowerPC::ppcState.pc))->type; + const OpType optype = + PPCTables::GetOpInfo(PowerPC::HostRead_U32(guard, PowerPC::ppcState.pc))->type; if (optype != OpType::Store && optype != OpType::StoreFP && optype != OpType::StorePS) return; } diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 318b41ddac..b8edb0defc 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -519,17 +519,18 @@ TryReadInstResult TryReadInstruction(u32 address) return TryReadInstResult{true, from_bat, hex, address}; } -u32 HostRead_Instruction(const u32 address) +u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); return ReadFromHardware(memory, address); } -std::optional> HostTryReadInstruction(const u32 address, +std::optional> HostTryReadInstruction(const Core::CPUThreadGuard& guard, + const u32 address, RequestedAddressSpace space) { - if (!HostIsInstructionRAMAddress(address, space)) + if (!HostIsInstructionRAMAddress(guard, address, space)) return std::nullopt; auto& system = Core::System::GetInstance(); @@ -648,9 +649,10 @@ float Read_F32(const u32 address) } template -static std::optional> HostTryReadUX(const u32 address, RequestedAddressSpace space) +static std::optional> HostTryReadUX(const Core::CPUThreadGuard& guard, + const u32 address, RequestedAddressSpace space) { - if (!HostIsRAMAddress(address, space)) + if (!HostIsRAMAddress(guard, address, space)) return std::nullopt; auto& system = Core::System::GetInstance(); @@ -681,37 +683,43 @@ static std::optional> HostTryReadUX(const u32 address, RequestedAd return std::nullopt; } -std::optional> HostTryReadU8(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadU8(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - return HostTryReadUX(address, space); + return HostTryReadUX(guard, address, space); } -std::optional> HostTryReadU16(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadU16(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - return HostTryReadUX(address, space); + return HostTryReadUX(guard, address, space); } -std::optional> HostTryReadU32(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadU32(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - return HostTryReadUX(address, space); + return HostTryReadUX(guard, address, space); } -std::optional> HostTryReadU64(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadU64(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - return HostTryReadUX(address, space); + return HostTryReadUX(guard, address, space); } -std::optional> HostTryReadF32(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadF32(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - const auto result = HostTryReadUX(address, space); + const auto result = HostTryReadUX(guard, address, space); if (!result) return std::nullopt; return ReadResult(result->translated, Common::BitCast(result->value)); } -std::optional> HostTryReadF64(u32 address, RequestedAddressSpace space) +std::optional> HostTryReadF64(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { - const auto result = HostTryReadUX(address, space); + const auto result = HostTryReadUX(guard, address, space); if (!result) return std::nullopt; return ReadResult(result->translated, Common::BitCast(result->value)); @@ -780,70 +788,70 @@ void Write_F64(const double var, const u32 address) Write_U64(integral, address); } -u8 HostRead_U8(const u32 address) +u8 HostRead_U8(const Core::CPUThreadGuard& guard, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); return ReadFromHardware(memory, address); } -u16 HostRead_U16(const u32 address) +u16 HostRead_U16(const Core::CPUThreadGuard& guard, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); return ReadFromHardware(memory, address); } -u32 HostRead_U32(const u32 address) +u32 HostRead_U32(const Core::CPUThreadGuard& guard, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); return ReadFromHardware(memory, address); } -u64 HostRead_U64(const u32 address) +u64 HostRead_U64(const Core::CPUThreadGuard& guard, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); return ReadFromHardware(memory, address); } -float HostRead_F32(const u32 address) +float HostRead_F32(const Core::CPUThreadGuard& guard, const u32 address) { - const u32 integral = HostRead_U32(address); + const u32 integral = HostRead_U32(guard, address); return Common::BitCast(integral); } -double HostRead_F64(const u32 address) +double HostRead_F64(const Core::CPUThreadGuard& guard, const u32 address) { - const u64 integral = HostRead_U64(address); + const u64 integral = HostRead_U64(guard, address); return Common::BitCast(integral); } -void HostWrite_U8(const u32 var, const u32 address) +void HostWrite_U8(const Core::CPUThreadGuard& guard, const u32 var, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); WriteToHardware(system, memory, address, var, 1); } -void HostWrite_U16(const u32 var, const u32 address) +void HostWrite_U16(const Core::CPUThreadGuard& guard, const u32 var, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); WriteToHardware(system, memory, address, var, 2); } -void HostWrite_U32(const u32 var, const u32 address) +void HostWrite_U32(const Core::CPUThreadGuard& guard, const u32 var, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); WriteToHardware(system, memory, address, var, 4); } -void HostWrite_U64(const u64 var, const u32 address) +void HostWrite_U64(const Core::CPUThreadGuard& guard, const u64 var, const u32 address) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); @@ -853,24 +861,25 @@ void HostWrite_U64(const u64 var, const u32 address) static_cast(var), 4); } -void HostWrite_F32(const float var, const u32 address) +void HostWrite_F32(const Core::CPUThreadGuard& guard, const float var, const u32 address) { const u32 integral = Common::BitCast(var); - HostWrite_U32(integral, address); + HostWrite_U32(guard, integral, address); } -void HostWrite_F64(const double var, const u32 address) +void HostWrite_F64(const Core::CPUThreadGuard& guard, const double var, const u32 address) { const u64 integral = Common::BitCast(var); - HostWrite_U64(integral, address); + HostWrite_U64(guard, integral, address); } -static std::optional HostTryWriteUX(const u32 var, const u32 address, const u32 size, +static std::optional HostTryWriteUX(const Core::CPUThreadGuard& guard, const u32 var, + const u32 address, const u32 size, RequestedAddressSpace space) { - if (!HostIsRAMAddress(address, space)) + if (!HostIsRAMAddress(guard, address, space)) return std::nullopt; auto& system = Core::System::GetInstance(); @@ -895,56 +904,56 @@ static std::optional HostTryWriteUX(const u32 var, const u32 addres return std::nullopt; } -std::optional HostTryWriteU8(const u32 var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteU8(const Core::CPUThreadGuard& guard, const u32 var, + const u32 address, RequestedAddressSpace space) { - return HostTryWriteUX(var, address, 1, space); + return HostTryWriteUX(guard, var, address, 1, space); } -std::optional HostTryWriteU16(const u32 var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteU16(const Core::CPUThreadGuard& guard, const u32 var, + const u32 address, RequestedAddressSpace space) { - return HostTryWriteUX(var, address, 2, space); + return HostTryWriteUX(guard, var, address, 2, space); } -std::optional HostTryWriteU32(const u32 var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteU32(const Core::CPUThreadGuard& guard, const u32 var, + const u32 address, RequestedAddressSpace space) { - return HostTryWriteUX(var, address, 4, space); + return HostTryWriteUX(guard, var, address, 4, space); } -std::optional HostTryWriteU64(const u64 var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteU64(const Core::CPUThreadGuard& guard, const u64 var, + const u32 address, RequestedAddressSpace space) { - const auto result = HostTryWriteUX(static_cast(var >> 32), address, 4, space); + const auto result = HostTryWriteUX(guard, static_cast(var >> 32), address, 4, space); if (!result) return result; - return HostTryWriteUX(static_cast(var), address + 4, 4, space); + return HostTryWriteUX(guard, static_cast(var), address + 4, 4, space); } -std::optional HostTryWriteF32(const float var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteF32(const Core::CPUThreadGuard& guard, const float var, + const u32 address, RequestedAddressSpace space) { const u32 integral = Common::BitCast(var); - return HostTryWriteU32(integral, address, space); + return HostTryWriteU32(guard, integral, address, space); } -std::optional HostTryWriteF64(const double var, const u32 address, - RequestedAddressSpace space) +std::optional HostTryWriteF64(const Core::CPUThreadGuard& guard, const double var, + const u32 address, RequestedAddressSpace space) { const u64 integral = Common::BitCast(var); - return HostTryWriteU64(integral, address, space); + return HostTryWriteU64(guard, integral, address, space); } -std::string HostGetString(u32 address, size_t size) +std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size) { std::string s; do { - if (!HostIsRAMAddress(address)) + if (!HostIsRAMAddress(guard, address)) break; - u8 res = HostRead_U8(address); + u8 res = HostRead_U8(guard, address); if (!res) break; s += static_cast(res); @@ -953,10 +962,11 @@ std::string HostGetString(u32 address, size_t size) return s; } -std::optional> HostTryReadString(u32 address, size_t size, +std::optional> HostTryReadString(const Core::CPUThreadGuard& guard, + u32 address, size_t size, RequestedAddressSpace space) { - auto c = HostTryReadU8(address, space); + auto c = HostTryReadU8(guard, address, space); if (!c) return std::nullopt; if (c->value == 0) @@ -967,7 +977,7 @@ std::optional> HostTryReadString(u32 address, size_t siz while (size == 0 || s.length() < size) { ++address; - const auto res = HostTryReadU8(address, space); + const auto res = HostTryReadU8(guard, address, space); if (!res || res->value == 0) break; s += static_cast(res->value); @@ -1024,7 +1034,7 @@ static bool IsRAMAddress(Memory::MemoryManager& memory, u32 address, bool transl return false; } -bool HostIsRAMAddress(u32 address, RequestedAddressSpace space) +bool HostIsRAMAddress(const Core::CPUThreadGuard& guard, u32 address, RequestedAddressSpace space) { auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); @@ -1045,7 +1055,8 @@ bool HostIsRAMAddress(u32 address, RequestedAddressSpace space) return false; } -bool HostIsInstructionRAMAddress(u32 address, RequestedAddressSpace space) +bool HostIsInstructionRAMAddress(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space) { // Instructions are always 32bit aligned. if (address & 3) diff --git a/Source/Core/Core/PowerPC/MMU.h b/Source/Core/Core/PowerPC/MMU.h index 44b9785611..bf9ee0d926 100644 --- a/Source/Core/Core/PowerPC/MMU.h +++ b/Source/Core/Core/PowerPC/MMU.h @@ -10,6 +10,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class CPUThreadGuard; +}; + namespace PowerPC { // Routines for debugger UI, cheats, etc. to access emulated memory from the @@ -27,14 +32,14 @@ enum class RequestedAddressSpace // If the read fails (eg. address does not correspond to a mapped address in the current address // space), a PanicAlert will be shown to the user and zero (or an empty string for the string case) // will be returned. -u8 HostRead_U8(u32 address); -u16 HostRead_U16(u32 address); -u32 HostRead_U32(u32 address); -u64 HostRead_U64(u32 address); -float HostRead_F32(u32 address); -double HostRead_F64(u32 address); -u32 HostRead_Instruction(u32 address); -std::string HostGetString(u32 address, size_t size = 0); +u8 HostRead_U8(const Core::CPUThreadGuard& guard, u32 address); +u16 HostRead_U16(const Core::CPUThreadGuard& guard, u32 address); +u32 HostRead_U32(const Core::CPUThreadGuard& guard, u32 address); +u64 HostRead_U64(const Core::CPUThreadGuard& guard, u32 address); +float HostRead_F32(const Core::CPUThreadGuard& guard, u32 address); +double HostRead_F64(const Core::CPUThreadGuard& guard, u32 address); +u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, u32 address); +std::string HostGetString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0); template struct ReadResult @@ -57,32 +62,39 @@ struct ReadResult // value and information on whether the given address had to be translated or not. Unlike the // HostRead functions, this does not raise a user-visible alert on failure. std::optional> -HostTryReadU8(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadU8(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadU16(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadU16(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadU32(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadU32(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadU64(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadU64(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadF32(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadF32(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadF64(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadF64(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadInstruction(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +HostTryReadInstruction(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional> -HostTryReadString(u32 address, size_t size = 0, +HostTryReadString(const Core::CPUThreadGuard& guard, u32 address, size_t size = 0, RequestedAddressSpace space = RequestedAddressSpace::Effective); // Writes a value to emulated memory using the currently active MMU settings. // If the write fails (eg. address does not correspond to a mapped address in the current address // space), a PanicAlert will be shown to the user. -void HostWrite_U8(u32 var, u32 address); -void HostWrite_U16(u32 var, u32 address); -void HostWrite_U32(u32 var, u32 address); -void HostWrite_U64(u64 var, u32 address); -void HostWrite_F32(float var, u32 address); -void HostWrite_F64(double var, u32 address); +void HostWrite_U8(const Core::CPUThreadGuard& guard, u32 var, u32 address); +void HostWrite_U16(const Core::CPUThreadGuard& guard, u32 var, u32 address); +void HostWrite_U32(const Core::CPUThreadGuard& guard, u32 var, u32 address); +void HostWrite_U64(const Core::CPUThreadGuard& guard, u64 var, u32 address); +void HostWrite_F32(const Core::CPUThreadGuard& guard, float var, u32 address); +void HostWrite_F64(const Core::CPUThreadGuard& guard, double var, u32 address); struct WriteResult { @@ -98,30 +110,31 @@ struct WriteResult // address had to be translated or not. Unlike the HostWrite functions, this does not raise a // user-visible alert on failure. std::optional -HostTryWriteU8(u32 var, const u32 address, +HostTryWriteU8(const Core::CPUThreadGuard& guard, u32 var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional -HostTryWriteU16(u32 var, const u32 address, +HostTryWriteU16(const Core::CPUThreadGuard& guard, u32 var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional -HostTryWriteU32(u32 var, const u32 address, +HostTryWriteU32(const Core::CPUThreadGuard& guard, u32 var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional -HostTryWriteU64(u64 var, const u32 address, +HostTryWriteU64(const Core::CPUThreadGuard& guard, u64 var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional -HostTryWriteF32(float var, const u32 address, +HostTryWriteF32(const Core::CPUThreadGuard& guard, float var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); std::optional -HostTryWriteF64(double var, const u32 address, +HostTryWriteF64(const Core::CPUThreadGuard& guard, double var, const u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); // Returns whether a read or write to the given address will resolve to a RAM access in the given // address space. -bool HostIsRAMAddress(u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); +bool HostIsRAMAddress(const Core::CPUThreadGuard& guard, u32 address, + RequestedAddressSpace space = RequestedAddressSpace::Effective); // Same as HostIsRAMAddress, but uses IBAT instead of DBAT. -bool HostIsInstructionRAMAddress(u32 address, +bool HostIsInstructionRAMAddress(const Core::CPUThreadGuard& guard, u32 address, RequestedAddressSpace space = RequestedAddressSpace::Effective); // Routines for the CPU core to access memory. diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index ee15a21052..1ce929e1bf 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -74,7 +74,8 @@ static u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc) // Also collect which internal branch goes the farthest. // If any one goes farther than the blr or rfi, assume that there is more than // one blr or rfi, and keep scanning. -bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size) +bool AnalyzeFunction(const Core::CPUThreadGuard& guard, u32 startAddr, Common::Symbol& func, + u32 max_size) { if (func.name.empty()) func.Rename(fmt::format("zz_{:08x}_", startAddr)); @@ -91,15 +92,18 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size) for (u32 addr = startAddr; true; addr += 4) { func.size += 4; - if (func.size >= JitBase::code_buffer_size * 4 || !PowerPC::HostIsInstructionRAMAddress(addr)) + if (func.size >= JitBase::code_buffer_size * 4 || + !PowerPC::HostIsInstructionRAMAddress(guard, addr)) + { return false; + } if (max_size && func.size > max_size) { func.address = startAddr; func.analyzed = true; func.size -= 4; - func.hash = HashSignatureDB::ComputeCodeChecksum(startAddr, addr - 4); + func.hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, addr - 4); if (numInternalBranches == 0) func.flags |= Common::FFLAG_STRAIGHT; return true; @@ -121,7 +125,7 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size) // Let's calc the checksum and get outta here func.address = startAddr; func.analyzed = true; - func.hash = HashSignatureDB::ComputeCodeChecksum(startAddr, addr); + func.hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, addr); if (numInternalBranches == 0) func.flags |= Common::FFLAG_STRAIGHT; return true; @@ -167,12 +171,13 @@ bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size) } } -bool ReanalyzeFunction(u32 start_addr, Common::Symbol& func, u32 max_size) +bool ReanalyzeFunction(const Core::CPUThreadGuard& guard, u32 start_addr, Common::Symbol& func, + u32 max_size) { ASSERT_MSG(SYMBOLS, func.analyzed, "The function wasn't previously analyzed!"); func.analyzed = false; - return AnalyzeFunction(start_addr, func, max_size); + return AnalyzeFunction(guard, start_addr, func, max_size); } // Second pass analysis, done after the first pass is done for all functions @@ -256,7 +261,8 @@ bool PPCAnalyzer::CanSwapAdjacentOps(const CodeOp& a, const CodeOp& b) const // called by another function. Therefore, let's scan the // entire space for bl operations and find what functions // get called. -static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::SymbolDB* func_db) +static void FindFunctionsFromBranches(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr, + Common::SymbolDB* func_db) { for (u32 addr = startAddr; addr < endAddr; addr += 4) { @@ -274,9 +280,9 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::Symbol u32 target = SignExt26(instr.LI << 2); if (!instr.AA) target += addr; - if (PowerPC::HostIsRAMAddress(target)) + if (PowerPC::HostIsRAMAddress(guard, target)) { - func_db->AddFunction(target); + func_db->AddFunction(guard, target); } } } @@ -288,7 +294,7 @@ static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, Common::Symbol } } -static void FindFunctionsFromHandlers(PPCSymbolDB* func_db) +static void FindFunctionsFromHandlers(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) { static const std::map handlers = { {0x80000100, "system_reset_exception_handler"}, @@ -314,7 +320,7 @@ static void FindFunctionsFromHandlers(PPCSymbolDB* func_db) if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex)) { // Check if this function is already mapped - Common::Symbol* f = func_db->AddFunction(entry.first); + Common::Symbol* f = func_db->AddFunction(guard, entry.first); if (!f) continue; f->Rename(entry.second); @@ -322,7 +328,8 @@ static void FindFunctionsFromHandlers(PPCSymbolDB* func_db) } } -static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db) +static void FindFunctionsAfterReturnInstruction(const Core::CPUThreadGuard& guard, + PPCSymbolDB* func_db) { std::vector funcAddrs; @@ -346,7 +353,7 @@ static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db) if (read_result.valid && PPCTables::IsValidInstruction(read_result.hex)) { // check if this function is already mapped - Common::Symbol* f = func_db->AddFunction(location); + Common::Symbol* f = func_db->AddFunction(guard, location); if (!f) break; else @@ -358,12 +365,13 @@ static void FindFunctionsAfterReturnInstruction(PPCSymbolDB* func_db) } } -void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db) +void FindFunctions(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr, + PPCSymbolDB* func_db) { // Step 1: Find all functions - FindFunctionsFromBranches(startAddr, endAddr, func_db); - FindFunctionsFromHandlers(func_db); - FindFunctionsAfterReturnInstruction(func_db); + FindFunctionsFromBranches(guard, startAddr, endAddr, func_db); + FindFunctionsFromHandlers(guard, func_db); + FindFunctionsAfterReturnInstruction(guard, func_db); // Step 2: func_db->FillInCallers(); diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h index 283706ebc1..f8ad657c60 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/PowerPC/PPCAnalyst.h @@ -19,6 +19,11 @@ namespace Common struct Symbol; } +namespace Core +{ +class CPUThreadGuard; +} + namespace PPCAnalyst { struct CodeOp // 16B @@ -201,8 +206,11 @@ private: bool m_enable_div_by_zero_exceptions = false; }; -void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db); -bool AnalyzeFunction(u32 startAddr, Common::Symbol& func, u32 max_size = 0); -bool ReanalyzeFunction(u32 start_addr, Common::Symbol& func, u32 max_size = 0); +void FindFunctions(const Core::CPUThreadGuard& guard, u32 startAddr, u32 endAddr, + PPCSymbolDB* func_db); +bool AnalyzeFunction(const Core::CPUThreadGuard& guard, u32 startAddr, Common::Symbol& func, + u32 max_size = 0); +bool ReanalyzeFunction(const Core::CPUThreadGuard& guard, u32 start_addr, Common::Symbol& func, + u32 max_size = 0); } // namespace PPCAnalyst diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index a1e5dd4fcc..c9ac1e7427 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -32,14 +32,14 @@ PPCSymbolDB::PPCSymbolDB() : debugger{&PowerPC::debug_interface} PPCSymbolDB::~PPCSymbolDB() = default; // Adds the function to the list, unless it's already there -Common::Symbol* PPCSymbolDB::AddFunction(u32 start_addr) +Common::Symbol* PPCSymbolDB::AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr) { // It's already in the list if (m_functions.find(start_addr) != m_functions.end()) return nullptr; Common::Symbol symbol; - if (!PPCAnalyst::AnalyzeFunction(start_addr, symbol)) + if (!PPCAnalyst::AnalyzeFunction(guard, start_addr, symbol)) return nullptr; m_functions[start_addr] = std::move(symbol); @@ -49,8 +49,8 @@ Common::Symbol* PPCSymbolDB::AddFunction(u32 start_addr) return ptr; } -void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, - Common::Symbol::Type type) +void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name, Common::Symbol::Type type) { auto iter = m_functions.find(startAddr); if (iter != m_functions.end()) @@ -58,7 +58,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam // already got it, let's just update name, checksum & size to be sure. Common::Symbol* tempfunc = &iter->second; tempfunc->Rename(name); - tempfunc->hash = HashSignatureDB::ComputeCodeChecksum(startAddr, startAddr + size - 4); + tempfunc->hash = HashSignatureDB::ComputeCodeChecksum(guard, startAddr, startAddr + size - 4); tempfunc->type = type; tempfunc->size = size; } @@ -71,7 +71,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam tf.address = startAddr; if (tf.type == Common::Symbol::Type::Function) { - PPCAnalyst::AnalyzeFunction(startAddr, tf, size); + PPCAnalyst::AnalyzeFunction(guard, startAddr, tf, size); // Do not truncate symbol when a size is expected if (size != 0 && tf.size != size) { @@ -224,7 +224,7 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) // This one can load both leftover map files on game discs (like Zelda), and mapfiles // produced by SaveSymbolMap below. // bad=true means carefully load map files that might not be from exactly the right version -bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) +bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad) { File::IOFile f(filename, "r"); if (!f) @@ -407,8 +407,8 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) if (strlen(name) > 0) { // Can't compute the checksum if not in RAM - bool good = !bad && PowerPC::HostIsInstructionRAMAddress(vaddress) && - PowerPC::HostIsInstructionRAMAddress(vaddress + size - 4); + bool good = !bad && PowerPC::HostIsInstructionRAMAddress(guard, vaddress) && + PowerPC::HostIsInstructionRAMAddress(guard, vaddress + size - 4); if (!good) { // check for BLR before function @@ -423,10 +423,10 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) if (good) { ++good_count; - if (section_name == ".text" || section_name == ".init") - AddKnownSymbol(vaddress, size, name, Common::Symbol::Type::Function); - else - AddKnownSymbol(vaddress, size, name, Common::Symbol::Type::Data); + const Common::Symbol::Type type = section_name == ".text" || section_name == ".init" ? + Common::Symbol::Type::Function : + Common::Symbol::Type::Data; + AddKnownSymbol(guard, vaddress, size, name, type); } else { @@ -485,7 +485,7 @@ bool PPCSymbolDB::SaveSymbolMap(const std::string& filename) const // Notes: // - Dolphin doesn't load back code maps // - It's a custom code map format -bool PPCSymbolDB::SaveCodeMap(const std::string& filename) const +bool PPCSymbolDB::SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const { constexpr int SYMBOL_NAME_LIMIT = 30; File::IOFile f(filename, "w"); @@ -515,7 +515,7 @@ bool PPCSymbolDB::SaveCodeMap(const std::string& filename) const // Write the code for (u32 address = symbol.address; address < next_address; address += 4) { - const std::string disasm = debugger->Disassemble(address); + const std::string disasm = debugger->Disassemble(&guard, address); f.WriteString(fmt::format("{0:08x} {1:<{2}.{3}} {4}\n", address, symbol.name, SYMBOL_NAME_LIMIT, SYMBOL_NAME_LIMIT, disasm)); } diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h index 7d62d53a43..2bf56d2de5 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -12,6 +12,11 @@ #include "Core/Debugger/PPCDebugInterface.h" +namespace Core +{ +class CPUThreadGuard; +} + // This has functionality overlapping Debugger_Symbolmap. Should merge that stuff in here later. class PPCSymbolDB : public Common::SymbolDB { @@ -19,8 +24,9 @@ public: PPCSymbolDB(); ~PPCSymbolDB() override; - Common::Symbol* AddFunction(u32 start_addr) override; - void AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, + Common::Symbol* AddFunction(const Core::CPUThreadGuard& guard, u32 start_addr) override; + void AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name, Common::Symbol::Type type = Common::Symbol::Type::Function); Common::Symbol* GetSymbolFromAddr(u32 addr) override; @@ -29,9 +35,9 @@ public: void FillInCallers(); - bool LoadMap(const std::string& filename, bool bad = false); + bool LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad = false); bool SaveSymbolMap(const std::string& filename) const; - bool SaveCodeMap(const std::string& filename) const; + bool SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const; void PrintCalls(u32 funcAddr) const; void PrintCallers(u32 funcAddr) const; diff --git a/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.cpp b/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.cpp index b12e7f1e6f..4d7c579a01 100644 --- a/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.cpp +++ b/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.cpp @@ -101,7 +101,7 @@ bool GetRefs(MEGASignature* sig, std::istringstream* iss) return true; } -bool Compare(u32 address, u32 size, const MEGASignature& sig) +bool Compare(const Core::CPUThreadGuard& guard, u32 address, u32 size, const MEGASignature& sig) { if (size != sig.code.size() * sizeof(u32)) return false; @@ -109,8 +109,10 @@ bool Compare(u32 address, u32 size, const MEGASignature& sig) for (size_t i = 0; i < sig.code.size(); ++i) { if (sig.code[i] != 0 && - PowerPC::HostRead_U32(static_cast(address + i * sizeof(u32))) != sig.code[i]) + PowerPC::HostRead_U32(guard, static_cast(address + i * sizeof(u32))) != sig.code[i]) + { return false; + } } return true; } @@ -156,14 +158,14 @@ bool MEGASignatureDB::Save(const std::string& file_path) const return false; } -void MEGASignatureDB::Apply(PPCSymbolDB* symbol_db) const +void MEGASignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const { for (auto& it : symbol_db->AccessSymbols()) { auto& symbol = it.second; for (const auto& sig : m_signatures) { - if (Compare(symbol.address, symbol.size, sig)) + if (Compare(guard, symbol.address, symbol.size, sig)) { symbol.name = sig.name; INFO_LOG_FMT(SYMBOLS, "Found {} at {:08x} (size: {:08x})!", sig.name, symbol.address, @@ -180,7 +182,8 @@ void MEGASignatureDB::Populate(const PPCSymbolDB* func_db, const std::string& fi ERROR_LOG_FMT(SYMBOLS, "MEGA database can't be populated yet."); } -bool MEGASignatureDB::Add(u32 startAddr, u32 size, const std::string& name) +bool MEGASignatureDB::Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name) { ERROR_LOG_FMT(SYMBOLS, "Can't add symbol to MEGA database yet."); return false; diff --git a/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.h b/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.h index 72b5c423dd..47add3d65c 100644 --- a/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.h +++ b/Source/Core/Core/PowerPC/SignatureDB/MEGASignatureDB.h @@ -9,6 +9,11 @@ #include "Common/CommonTypes.h" #include "Core/PowerPC/SignatureDB/SignatureDB.h" +namespace Core +{ +class CPUThreadGuard; +} + class PPCSymbolDB; struct MEGASignatureReference @@ -46,10 +51,11 @@ public: bool Save(const std::string& file_path) const override; void List() const override; - void Apply(PPCSymbolDB* symbol_db) const override; + void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const override; void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override; - bool Add(u32 startAddr, u32 size, const std::string& name) override; + bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name) override; private: std::vector m_signatures; diff --git a/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.cpp b/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.cpp index 5634c7f60f..afe09acfa2 100644 --- a/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.cpp +++ b/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.cpp @@ -76,20 +76,22 @@ void SignatureDB::Populate(const PPCSymbolDB* func_db, const std::string& filter m_handler->Populate(func_db, filter); } -void SignatureDB::Apply(PPCSymbolDB* func_db) const +void SignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const { - m_handler->Apply(func_db); + m_handler->Apply(guard, func_db); } -bool SignatureDB::Add(u32 start_addr, u32 size, const std::string& name) +bool SignatureDB::Add(const Core::CPUThreadGuard& guard, u32 start_addr, u32 size, + const std::string& name) { - return m_handler->Add(start_addr, size, name); + return m_handler->Add(guard, start_addr, size, name); } // Adds a known function to the hash database -bool HashSignatureDB::Add(u32 startAddr, u32 size, const std::string& name) +bool HashSignatureDB::Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name) { - u32 hash = ComputeCodeChecksum(startAddr, startAddr + size - 4); + u32 hash = ComputeCodeChecksum(guard, startAddr, startAddr + size - 4); DBFunc temp_dbfunc; temp_dbfunc.size = size; @@ -119,7 +121,7 @@ void HashSignatureDB::Clear() m_database.clear(); } -void HashSignatureDB::Apply(PPCSymbolDB* symbol_db) const +void HashSignatureDB::Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* symbol_db) const { for (const auto& entry : m_database) { @@ -158,12 +160,13 @@ void HashSignatureDB::Populate(const PPCSymbolDB* symbol_db, const std::string& } } -u32 HashSignatureDB::ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd) +u32 HashSignatureDB::ComputeCodeChecksum(const Core::CPUThreadGuard& guard, u32 offsetStart, + u32 offsetEnd) { u32 sum = 0; for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4) { - u32 opcode = PowerPC::HostRead_Instruction(offset); + u32 opcode = PowerPC::HostRead_Instruction(guard, offset); u32 op = opcode & 0xFC000000; u32 op2 = 0; u32 op3 = 0; diff --git a/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.h b/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.h index 5b5fe85a6a..054b4e98d1 100644 --- a/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.h +++ b/Source/Core/Core/PowerPC/SignatureDB/SignatureDB.h @@ -11,6 +11,11 @@ // You're not meant to keep around SignatureDB objects persistently. Use 'em, throw them away. +namespace Core +{ +class CPUThreadGuard; +} + class PPCSymbolDB; class SignatureDBFormatHandler; @@ -33,9 +38,9 @@ public: void List() const; void Populate(const PPCSymbolDB* func_db, const std::string& filter = ""); - void Apply(PPCSymbolDB* func_db) const; + void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const; - bool Add(u32 start_addr, u32 size, const std::string& name); + bool Add(const Core::CPUThreadGuard& guard, u32 start_addr, u32 size, const std::string& name); private: std::unique_ptr m_handler; @@ -52,9 +57,10 @@ public: virtual void List() const = 0; virtual void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") = 0; - virtual void Apply(PPCSymbolDB* func_db) const = 0; + virtual void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const = 0; - virtual bool Add(u32 startAddr, u32 size, const std::string& name) = 0; + virtual bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name) = 0; }; class HashSignatureDB : public SignatureDBFormatHandler @@ -69,15 +75,16 @@ public: }; using FuncDB = std::map; - static u32 ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd); + static u32 ComputeCodeChecksum(const Core::CPUThreadGuard& guard, u32 offsetStart, u32 offsetEnd); void Clear() override; void List() const override; void Populate(const PPCSymbolDB* func_db, const std::string& filter = "") override; - void Apply(PPCSymbolDB* func_db) const override; + void Apply(const Core::CPUThreadGuard& guard, PPCSymbolDB* func_db) const override; - bool Add(u32 startAddr, u32 size, const std::string& name) override; + bool Add(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, + const std::string& name) override; protected: // Map from signature to function. We store the DB in this map because it optimizes the diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 6469607cc1..4b265599d8 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -477,30 +477,31 @@ void ApplyPatchesToFiles(const std::vector& patches, PatchIndex index, } } -static bool MemoryMatchesAt(u32 offset, const std::vector& value) +static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset, + const std::vector& value) { for (u32 i = 0; i < value.size(); ++i) { - auto result = PowerPC::HostTryReadU8(offset + i); + auto result = PowerPC::HostTryReadU8(guard, offset + i); if (!result || result->value != value[i]) return false; } return true; } -static void ApplyMemoryPatch(u32 offset, const std::vector& value, - const std::vector& original) +static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset, + const std::vector& value, const std::vector& original) { if (value.empty()) return; - if (!original.empty() && !MemoryMatchesAt(offset, original)) + if (!original.empty() && !MemoryMatchesAt(guard, offset, original)) return; auto& system = Core::System::GetInstance(); const u32 size = static_cast(value.size()); for (u32 i = 0; i < size; ++i) - PowerPC::HostTryWriteU8(value[i], offset + i); + PowerPC::HostTryWriteU8(guard, value[i], offset + i); const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size); if (overlapping_hook_count != 0) { @@ -516,17 +517,18 @@ static std::vector GetMemoryPatchValue(const Patch& patch, const Memory& mem return memory_patch.m_value; } -static void ApplyMemoryPatch(const Patch& patch, const Memory& memory_patch) +static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, + const Memory& memory_patch) { if (memory_patch.m_offset == 0) return; - ApplyMemoryPatch(memory_patch.m_offset | 0x80000000, GetMemoryPatchValue(patch, memory_patch), - memory_patch.m_original); + ApplyMemoryPatch(guard, memory_patch.m_offset | 0x80000000, + GetMemoryPatchValue(patch, memory_patch), memory_patch.m_original); } -static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, - u32 length) +static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, + const Memory& memory_patch, u32 ram_start, u32 length) { if (memory_patch.m_original.empty() || memory_patch.m_align == 0) return; @@ -535,16 +537,16 @@ static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patc for (u32 i = 0; i < length - (stride - 1); i += stride) { const u32 address = ram_start + i; - if (MemoryMatchesAt(address, memory_patch.m_original)) + if (MemoryMatchesAt(guard, address, memory_patch.m_original)) { - ApplyMemoryPatch(address, GetMemoryPatchValue(patch, memory_patch), {}); + ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch), {}); break; } } } -static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, - u32 length) +static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, + const Memory& memory_patch, u32 ram_start, u32 length) { if (memory_patch.m_offset == 0) return; @@ -557,19 +559,19 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat { // first find the pattern const u32 address = ram_start + i; - if (MemoryMatchesAt(address, value)) + if (MemoryMatchesAt(guard, address, value)) { for (; i < length; i += 4) { // from the pattern find the next blr instruction const u32 blr_address = ram_start + i; - auto blr = PowerPC::HostTryReadU32(blr_address); + auto blr = PowerPC::HostTryReadU32(guard, blr_address); if (blr && blr->value == 0x4e800020) { // and replace it with a jump to the given offset const u32 target = memory_patch.m_offset | 0x80000000; const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000; - PowerPC::HostTryWriteU32(jmp, blr_address); + PowerPC::HostTryWriteU32(guard, jmp, blr_address); const u32 overlapping_hook_count = HLE::UnpatchRange(system, blr_address, blr_address + 4); if (overlapping_hook_count != 0) @@ -584,7 +586,7 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat } } -void ApplyGeneralMemoryPatches(const std::vector& patches) +void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, const std::vector& patches) { auto& system = Core::System::GetInstance(); auto& system_memory = system.GetMemory(); @@ -597,14 +599,15 @@ void ApplyGeneralMemoryPatches(const std::vector& patches) continue; if (memory.m_search) - ApplySearchMemoryPatch(patch, memory, 0x80000000, system_memory.GetRamSize()); + ApplySearchMemoryPatch(guard, patch, memory, 0x80000000, system_memory.GetRamSize()); else - ApplyMemoryPatch(patch, memory); + ApplyMemoryPatch(guard, patch, memory); } } } -void ApplyApploaderMemoryPatches(const std::vector& patches, u32 ram_address, u32 ram_length) +void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, + const std::vector& patches, u32 ram_address, u32 ram_length) { for (const auto& patch : patches) { @@ -614,9 +617,9 @@ void ApplyApploaderMemoryPatches(const std::vector& patches, u32 ram_addr continue; if (memory.m_ocarina) - ApplyOcarinaMemoryPatch(patch, memory, ram_address, ram_length); + ApplyOcarinaMemoryPatch(guard, patch, memory, ram_address, ram_length); else - ApplySearchMemoryPatch(patch, memory, ram_address, ram_length); + ApplySearchMemoryPatch(guard, patch, memory, ram_address, ram_length); } } } diff --git a/Source/Core/DiscIO/RiivolutionPatcher.h b/Source/Core/DiscIO/RiivolutionPatcher.h index 0a83ba9d13..d83c51d686 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.h +++ b/Source/Core/DiscIO/RiivolutionPatcher.h @@ -11,6 +11,11 @@ #include "DiscIO/DirectoryBlob.h" #include "DiscIO/RiivolutionParser.h" +namespace Core +{ +class CPUThreadGuard; +} + namespace DiscIO::Riivolution { struct SavegameRedirect @@ -74,8 +79,10 @@ enum class PatchIndex void ApplyPatchesToFiles(const std::vector& patches, PatchIndex index, std::vector* fst, DiscIO::FSTBuilderNode* dol_node); -void ApplyGeneralMemoryPatches(const std::vector& patches); -void ApplyApploaderMemoryPatches(const std::vector& patches, u32 ram_address, +void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, + const std::vector& patches); +void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard, + const std::vector& patches, u32 ram_address, u32 ram_length); std::optional ExtractSavegameRedirect(const std::vector& riivolution_patches); diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index e4e81b3820..66f44c7ee8 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -36,6 +36,7 @@ #include "Core/CheatGeneration.h" #include "Core/CheatSearch.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/PowerPC/PowerPC.h" #include "DolphinQt/Config/CheatCodeEditor.h" @@ -286,7 +287,11 @@ void CheatSearchWidget::OnNextScanClicked() return; } } - Cheats::SearchErrorCode error_code = m_session->RunSearch(); + + const Cheats::SearchErrorCode error_code = [this] { + Core::CPUThreadGuard guard; + return m_session->RunSearch(guard); + }(); if (error_code == Cheats::SearchErrorCode::Success) { @@ -391,7 +396,13 @@ bool CheatSearchWidget::RefreshValues() } tmp->SetFilterType(Cheats::FilterType::DoNotFilter); - if (tmp->RunSearch() != Cheats::SearchErrorCode::Success) + + const Cheats::SearchErrorCode error_code = [&tmp] { + Core::CPUThreadGuard guard; + return tmp->RunSearch(guard); + }(); + + if (error_code != Cheats::SearchErrorCode::Success) { m_info_label_1->setText(tr("Refresh failed. Please run the game for a bit and try again.")); return false; diff --git a/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp b/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp index bb2fc03c1b..a3d1ddec26 100644 --- a/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp @@ -483,7 +483,11 @@ void CodeDiffDialog::OnSetBLR() Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(item->data(Qt::UserRole).toUInt()); if (!symbol) return; - PowerPC::debug_interface.SetPatch(symbol->address, 0x4E800020); + + { + Core::CPUThreadGuard guard; + PowerPC::debug_interface.SetPatch(guard, symbol->address, 0x4E800020); + } int row = item->row(); m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red)); diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index b4cfcb19eb..a505060566 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -175,14 +175,15 @@ CodeViewWidget::CodeViewWidget() Update(); }); - connect(&Settings::Instance(), &Settings::ThemeChanged, this, &CodeViewWidget::Update); + connect(&Settings::Instance(), &Settings::ThemeChanged, this, + qOverload<>(&CodeViewWidget::Update)); } CodeViewWidget::~CodeViewWidget() = default; -static u32 GetBranchFromAddress(u32 addr) +static u32 GetBranchFromAddress(const Core::CPUThreadGuard& guard, u32 addr) { - std::string disasm = PowerPC::debug_interface.Disassemble(addr); + std::string disasm = PowerPC::debug_interface.Disassemble(&guard, addr); size_t pos = disasm.find("->0x"); if (pos == std::string::npos) @@ -248,6 +249,26 @@ static bool IsInstructionLoadStore(std::string_view ins) } void CodeViewWidget::Update() +{ + if (!isVisible()) + return; + + if (m_updating) + return; + + if (Core::GetState() == Core::State::Paused) + { + Core::CPUThreadGuard guard; + Update(&guard); + } + else + { + // If the core is running, blank out the view of memory instead of reading anything. + Update(nullptr); + } +} + +void CodeViewWidget::Update(const Core::CPUThreadGuard* guard) { if (!isVisible()) return; @@ -284,11 +305,11 @@ void CodeViewWidget::Update() for (int i = 0; i < rowCount(); i++) { const u32 addr = AddressForRow(i); - const u32 color = PowerPC::debug_interface.GetColor(addr); + const u32 color = PowerPC::debug_interface.GetColor(guard, addr); auto* bp_item = new QTableWidgetItem; auto* addr_item = new QTableWidgetItem(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0'))); - std::string disas = PowerPC::debug_interface.Disassemble(addr); + std::string disas = PowerPC::debug_interface.Disassemble(guard, addr); auto split = disas.find('\t'); std::string ins = (split == std::string::npos ? disas : disas.substr(0, split)); @@ -332,9 +353,9 @@ void CodeViewWidget::Update() hex_str = param.substr(pos); } - if (hex_str.length() == VALID_BRANCH_LENGTH && desc != "---") + if (guard && hex_str.length() == VALID_BRANCH_LENGTH && desc != "---") { - u32 branch_addr = GetBranchFromAddress(addr); + u32 branch_addr = GetBranchFromAddress(*guard, addr); CodeViewBranch& branch = m_branches.emplace_back(); branch.src_addr = addr; branch.dst_addr = branch_addr; @@ -514,15 +535,20 @@ void CodeViewWidget::SetAddress(u32 address, SetAddressUpdate update) void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace) { - PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000); - Update(); + Core::CPUThreadGuard guard; + + PowerPC::debug_interface.SetPatch(guard, address, + replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000); + + Update(&guard); } void CodeViewWidget::OnContextMenu() { QMenu* menu = new QMenu(this); - bool running = Core::GetState() != Core::State::Uninitialized; + const bool running = Core::GetState() != Core::State::Uninitialized; + const bool paused = Core::GetState() == Core::State::Paused; const u32 addr = GetContextAddress(); @@ -567,14 +593,25 @@ void CodeViewWidget::OnContextMenu() menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction); QString target; - if (addr == PowerPC::ppcState.pc && running && Core::GetState() == Core::State::Paused) + bool valid_load_store = false; + bool follow_branch_enabled = false; + if (paused) { - const std::string line = PowerPC::debug_interface.Disassemble(PowerPC::ppcState.pc); - const auto target_it = std::find(line.begin(), line.end(), '\t'); - const auto target_end = std::find(target_it, line.end(), ','); + Core::CPUThreadGuard guard; + const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, PowerPC::ppcState.pc); - if (target_it != line.end() && target_end != line.end()) - target = QString::fromStdString(std::string{target_it + 1, target_end}); + if (addr == PowerPC::ppcState.pc) + { + const auto target_it = std::find(disasm.begin(), disasm.end(), '\t'); + const auto target_end = std::find(target_it, disasm.end(), ','); + + if (target_it != disasm.end() && target_end != disasm.end()) + target = QString::fromStdString(std::string{target_it + 1, target_end}); + } + + valid_load_store = IsInstructionLoadStore(disasm); + + follow_branch_enabled = GetBranchFromAddress(guard, addr); } auto* run_until_menu = menu->addMenu(tr("Run until (ignoring breakpoints)")); @@ -589,18 +626,17 @@ void CodeViewWidget::OnContextMenu() [this] { AutoStep(CodeTrace::AutoStop::Changed); }); run_until_menu->setEnabled(!target.isEmpty()); - follow_branch_action->setEnabled(running && GetBranchFromAddress(addr)); + follow_branch_action->setEnabled(follow_branch_enabled); for (auto* action : {copy_address_action, copy_line_action, copy_hex_action, function_action, ppc_action, insert_blr_action, insert_nop_action, replace_action}) + { action->setEnabled(running); + } for (auto* action : {symbol_rename_action, symbol_size_action, symbol_end_action}) action->setEnabled(has_symbol); - const bool valid_load_store = Core::GetState() == Core::State::Paused && - IsInstructionLoadStore(PowerPC::debug_interface.Disassemble(addr)); - for (auto* action : {copy_target_memory, show_target_memory}) { action->setEnabled(valid_load_store); @@ -617,6 +653,8 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option) // Autosteps and follows value in the target (left-most) register. The Used and Changed options // silently follows target through reshuffles in memory and registers and stops on use or update. + Core::CPUThreadGuard guard; + CodeTrace code_trace; bool repeat = false; @@ -628,7 +666,7 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option) do { // Run autostep then update codeview - const AutoStepResults results = code_trace.AutoStepping(repeat, option); + const AutoStepResults results = code_trace.AutoStepping(guard, repeat, option); emit Host::GetInstance()->UpdateDisasmDialog(); repeat = true; @@ -703,16 +741,24 @@ void CodeViewWidget::OnCopyTargetAddress() if (Core::GetState() != Core::State::Paused) return; - const std::string code_line = PowerPC::debug_interface.Disassemble(GetContextAddress()); + const u32 addr = GetContextAddress(); + + const std::string code_line = [addr] { + Core::CPUThreadGuard guard; + return PowerPC::debug_interface.Disassemble(&guard, addr); + }(); if (!IsInstructionLoadStore(code_line)) return; - const std::optional addr = + const std::optional target_addr = PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line); if (addr) - QApplication::clipboard()->setText(QStringLiteral("%1").arg(*addr, 8, 16, QLatin1Char('0'))); + { + QApplication::clipboard()->setText( + QStringLiteral("%1").arg(*target_addr, 8, 16, QLatin1Char('0'))); + } } void CodeViewWidget::OnShowInMemory() @@ -725,24 +771,33 @@ void CodeViewWidget::OnShowTargetInMemory() if (Core::GetState() != Core::State::Paused) return; - const std::string code_line = PowerPC::debug_interface.Disassemble(GetContextAddress()); + const u32 addr = GetContextAddress(); + + const std::string code_line = [addr] { + Core::CPUThreadGuard guard; + return PowerPC::debug_interface.Disassemble(&guard, addr); + }(); if (!IsInstructionLoadStore(code_line)) return; - const std::optional addr = + const std::optional target_addr = PowerPC::debug_interface.GetMemoryAddressFromInstruction(code_line); if (addr) - emit ShowMemory(*addr); + emit ShowMemory(*target_addr); } void CodeViewWidget::OnCopyCode() { const u32 addr = GetContextAddress(); - QApplication::clipboard()->setText( - QString::fromStdString(PowerPC::debug_interface.Disassemble(addr))); + const std::string text = [addr] { + Core::CPUThreadGuard guard; + return PowerPC::debug_interface.Disassemble(&guard, addr); + }(); + + QApplication::clipboard()->setText(QString::fromStdString(text)); } void CodeViewWidget::OnCopyFunction() @@ -754,13 +809,18 @@ void CodeViewWidget::OnCopyFunction() return; std::string text = symbol->name + "\r\n"; - // we got a function - const u32 start = symbol->address; - const u32 end = start + symbol->size; - for (u32 addr = start; addr != end; addr += 4) + { - const std::string disasm = PowerPC::debug_interface.Disassemble(addr); - fmt::format_to(std::back_inserter(text), "{:08x}: {}\r\n", addr, disasm); + Core::CPUThreadGuard guard; + + // we got a function + const u32 start = symbol->address; + const u32 end = start + symbol->size; + for (u32 addr = start; addr != end; addr += 4) + { + const std::string disasm = PowerPC::debug_interface.Disassemble(&guard, addr); + fmt::format_to(std::back_inserter(text), "{:08x}: {}\r\n", addr, disasm); + } } QApplication::clipboard()->setText(QString::fromStdString(text)); @@ -769,7 +829,11 @@ void CodeViewWidget::OnCopyFunction() void CodeViewWidget::OnCopyHex() { const u32 addr = GetContextAddress(); - const u32 instruction = PowerPC::debug_interface.ReadInstruction(addr); + + const u32 instruction = [addr] { + Core::CPUThreadGuard guard; + return PowerPC::debug_interface.ReadInstruction(guard, addr); + }(); QApplication::clipboard()->setText( QStringLiteral("%1").arg(instruction, 8, 16, QLatin1Char('0'))); @@ -795,9 +859,11 @@ void CodeViewWidget::OnAddFunction() { const u32 addr = GetContextAddress(); - g_symbolDB.AddFunction(addr); + Core::CPUThreadGuard guard; + + g_symbolDB.AddFunction(guard, addr); emit SymbolsChanged(); - Update(); + Update(&guard); } void CodeViewWidget::OnInsertBLR() @@ -818,7 +884,10 @@ void CodeViewWidget::OnFollowBranch() { const u32 addr = GetContextAddress(); - u32 branch_addr = GetBranchFromAddress(addr); + const u32 branch_addr = [addr] { + Core::CPUThreadGuard guard; + return GetBranchFromAddress(guard, addr); + }(); if (!branch_addr) return; @@ -879,9 +948,11 @@ void CodeViewWidget::OnSetSymbolSize() if (!good) return; - PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, size); + Core::CPUThreadGuard guard; + + PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size); emit SymbolsChanged(); - Update(); + Update(&guard); } void CodeViewWidget::OnSetSymbolEndAddress() @@ -905,37 +976,43 @@ void CodeViewWidget::OnSetSymbolEndAddress() if (!good) return; - PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, address - symbol->address); + Core::CPUThreadGuard guard; + + PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address); emit SymbolsChanged(); - Update(); + Update(&guard); } void CodeViewWidget::OnReplaceInstruction() { + Core::CPUThreadGuard guard; + const u32 addr = GetContextAddress(); - if (!PowerPC::HostIsInstructionRAMAddress(addr)) + if (!PowerPC::HostIsInstructionRAMAddress(guard, addr)) return; const PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(addr); if (!read_result.valid) return; - PatchInstructionDialog dialog(this, addr, PowerPC::debug_interface.ReadInstruction(addr)); + PatchInstructionDialog dialog(this, addr, PowerPC::debug_interface.ReadInstruction(guard, addr)); if (dialog.exec() == QDialog::Accepted) { - PowerPC::debug_interface.SetPatch(addr, dialog.GetCode()); - Update(); + PowerPC::debug_interface.SetPatch(guard, addr, dialog.GetCode()); + Update(&guard); } } void CodeViewWidget::OnRestoreInstruction() { + Core::CPUThreadGuard guard; + const u32 addr = GetContextAddress(); - PowerPC::debug_interface.UnsetPatch(addr); - Update(); + PowerPC::debug_interface.UnsetPatch(guard, addr); + Update(&guard); } void CodeViewWidget::resizeEvent(QResizeEvent*) diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.h b/Source/Core/DolphinQt/Debugger/CodeViewWidget.h index 33f34f3fc8..bf06b1e91d 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.h @@ -15,6 +15,11 @@ class QMouseEvent; class QResizeEvent; class QShowEvent; +namespace Core +{ +class CPUThreadGuard; +}; + struct CodeViewBranch; class BranchDisplayDelegate; @@ -39,6 +44,7 @@ public: // Set tighter row height. Set BP column sizing. This needs to run when font type changes. void FontBasedSizing(); void Update(); + void Update(const Core::CPUThreadGuard* guard); void ToggleBreakpoint(); void AddBreakpoint(); diff --git a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp index 5f7229ce65..513a68672d 100644 --- a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp @@ -329,7 +329,10 @@ void CodeWidget::UpdateCallstack() std::vector stack; - bool success = Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), stack); + const bool success = [&stack] { + Core::CPUThreadGuard guard; + return Dolphin_Debugger::GetCallstack(Core::System::GetInstance(), guard, stack); + }(); if (!success) { @@ -452,7 +455,11 @@ void CodeWidget::StepOver() if (!CPU::IsStepping()) return; - UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc); + const UGeckoInstruction inst = [] { + Core::CPUThreadGuard guard; + return PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc); + }(); + if (inst.LK) { PowerPC::breakpoints.ClearAllTemporary(); @@ -485,48 +492,51 @@ void CodeWidget::StepOut() if (!CPU::IsStepping()) return; - CPU::PauseAndLock(true, false); - PowerPC::breakpoints.ClearAllTemporary(); - // Keep stepping until the next return instruction or timeout after five seconds using clock = std::chrono::steady_clock; clock::time_point timeout = clock::now() + std::chrono::seconds(5); - PowerPC::CoreMode old_mode = PowerPC::GetMode(); - PowerPC::SetMode(PowerPC::CoreMode::Interpreter); - // Loop until either the current instruction is a return instruction with no Link flag - // or a breakpoint is detected so it can step at the breakpoint. If the PC is currently - // on a breakpoint, skip it. - UGeckoInstruction inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc); - do { - if (WillInstructionReturn(inst)) - { - PowerPC::SingleStep(); - break; - } + Core::CPUThreadGuard guard; - if (inst.LK) + PowerPC::breakpoints.ClearAllTemporary(); + + PowerPC::CoreMode old_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::CoreMode::Interpreter); + + // Loop until either the current instruction is a return instruction with no Link flag + // or a breakpoint is detected so it can step at the breakpoint. If the PC is currently + // on a breakpoint, skip it. + UGeckoInstruction inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc); + do { - // Step over branches - u32 next_pc = PowerPC::ppcState.pc + 4; - do + if (WillInstructionReturn(inst)) { PowerPC::SingleStep(); - } while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout && - !PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); - } - else - { - PowerPC::SingleStep(); - } + break; + } - inst = PowerPC::HostRead_Instruction(PowerPC::ppcState.pc); - } while (clock::now() < timeout && - !PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); + if (inst.LK) + { + // Step over branches + u32 next_pc = PowerPC::ppcState.pc + 4; + do + { + PowerPC::SingleStep(); + } while (PowerPC::ppcState.pc != next_pc && clock::now() < timeout && + !PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); + } + else + { + PowerPC::SingleStep(); + } - PowerPC::SetMode(old_mode); - CPU::PauseAndLock(false, false); + inst = PowerPC::HostRead_Instruction(guard, PowerPC::ppcState.pc); + } while (clock::now() < timeout && + !PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc)); + + PowerPC::SetMode(old_mode); + } emit Host::GetInstance()->UpdateDisasmDialog(); diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp index e99c7a8755..6c08d9a403 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp @@ -18,6 +18,7 @@ #include #include "Common/Align.h" +#include "Common/Assert.h" #include "Common/FloatUtils.h" #include "Common/StringUtil.h" #include "Common/Swap.h" @@ -46,6 +47,8 @@ constexpr int SCROLLBAR_PAGESTEP = 250; constexpr int SCROLLBAR_MAXIMUM = 20000; constexpr int SCROLLBAR_CENTER = SCROLLBAR_MAXIMUM / 2; +const QString INVALID_MEMORY = QStringLiteral("-"); + class MemoryViewTable final : public QTableWidget { public: @@ -151,11 +154,13 @@ public: u32 end_address = address + static_cast(bytes.size()) - 1; AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_view->GetAddressSpace()); - if (!bytes.empty() && accessors->IsValidAddress(address) && - accessors->IsValidAddress(end_address)) + Core::CPUThreadGuard guard; + + if (!bytes.empty() && accessors->IsValidAddress(guard, address) && + accessors->IsValidAddress(guard, end_address)) { for (const u8 c : bytes) - accessors->WriteU8(address++, c); + accessors->WriteU8(guard, address++, c); } m_view->Update(); @@ -190,8 +195,9 @@ MemoryViewWidget::MemoryViewWidget(QWidget* parent) : QWidget(parent) connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, - &MemoryViewWidget::UpdateColumns); - connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &MemoryViewWidget::UpdateColumns); + qOverload<>(&MemoryViewWidget::UpdateColumns)); + connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, + qOverload<>(&MemoryViewWidget::UpdateColumns)); connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update); // Also calls create table. @@ -322,13 +328,13 @@ void MemoryViewWidget::CreateTable() bp_item->setData(USER_ROLE_VALUE_TYPE, static_cast(Type::Null)); // Row Addresses - auto* row_item = new QTableWidgetItem(QStringLiteral("-")); + auto* row_item = new QTableWidgetItem(INVALID_MEMORY); row_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); row_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); row_item->setData(USER_ROLE_VALUE_TYPE, static_cast(Type::Null)); // Data item - auto* item = new QTableWidgetItem(QStringLiteral("-")); + auto* item = new QTableWidgetItem(INVALID_MEMORY); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); @@ -430,6 +436,24 @@ void MemoryViewWidget::Update() } void MemoryViewWidget::UpdateColumns() +{ + // Check if table is created + if (m_table->item(1, 1) == nullptr) + return; + + if (Core::GetState() == Core::State::Paused) + { + Core::CPUThreadGuard guard; + UpdateColumns(&guard); + } + else + { + // If the core is running, blank out the view of memory instead of reading anything. + UpdateColumns(nullptr); + } +} + +void MemoryViewWidget::UpdateColumns(const Core::CPUThreadGuard* guard) { // Check if table is created if (m_table->item(1, 1) == nullptr) @@ -445,7 +469,7 @@ void MemoryViewWidget::UpdateColumns() const u32 cell_address = cell_item->data(USER_ROLE_CELL_ADDRESS).toUInt(); const Type type = static_cast(cell_item->data(USER_ROLE_VALUE_TYPE).toInt()); - cell_item->setText(ValueToString(cell_address, type)); + cell_item->setText(guard ? ValueToString(*guard, cell_address, type) : INVALID_MEMORY); // Set search address to selected / colored if (cell_address == m_address_highlight) @@ -454,55 +478,56 @@ void MemoryViewWidget::UpdateColumns() } } -QString MemoryViewWidget::ValueToString(u32 address, Type type) +// May only be called if we have taken on the role of the CPU thread +QString MemoryViewWidget::ValueToString(const Core::CPUThreadGuard& guard, u32 address, Type type) { const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); - if (!accessors->IsValidAddress(address) || Core::GetState() != Core::State::Paused) - return QStringLiteral("-"); + if (!accessors->IsValidAddress(guard, address)) + return INVALID_MEMORY; switch (type) { case Type::Hex8: { - const u8 value = accessors->ReadU8(address); + const u8 value = accessors->ReadU8(guard, address); return QStringLiteral("%1").arg(value, 2, 16, QLatin1Char('0')); } case Type::ASCII: { - const char value = accessors->ReadU8(address); + const char value = accessors->ReadU8(guard, address); return IsPrintableCharacter(value) ? QString{QChar::fromLatin1(value)} : QString{QChar::fromLatin1('.')}; } case Type::Hex16: { - const u16 value = accessors->ReadU16(address); + const u16 value = accessors->ReadU16(guard, address); return QStringLiteral("%1").arg(value, 4, 16, QLatin1Char('0')); } case Type::Hex32: { - const u32 value = accessors->ReadU32(address); + const u32 value = accessors->ReadU32(guard, address); return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0')); } case Type::Hex64: { - const u64 value = accessors->ReadU64(address); + const u64 value = accessors->ReadU64(guard, address); return QStringLiteral("%1").arg(value, 16, 16, QLatin1Char('0')); } case Type::Unsigned8: - return QString::number(accessors->ReadU8(address)); + return QString::number(accessors->ReadU8(guard, address)); case Type::Unsigned16: - return QString::number(accessors->ReadU16(address)); + return QString::number(accessors->ReadU16(guard, address)); case Type::Unsigned32: - return QString::number(accessors->ReadU32(address)); + return QString::number(accessors->ReadU32(guard, address)); case Type::Signed8: - return QString::number(Common::BitCast(accessors->ReadU8(address))); + return QString::number(Common::BitCast(accessors->ReadU8(guard, address))); case Type::Signed16: - return QString::number(Common::BitCast(accessors->ReadU16(address))); + return QString::number(Common::BitCast(accessors->ReadU16(guard, address))); case Type::Signed32: - return QString::number(Common::BitCast(accessors->ReadU32(address))); + return QString::number(Common::BitCast(accessors->ReadU32(guard, address))); case Type::Float32: { - QString string = QString::number(accessors->ReadF32(address), 'g', 4); + QString string = QString::number(accessors->ReadF32(guard, address), 'g', 4); // Align to first digit. if (!string.startsWith(QLatin1Char('-'))) string.prepend(QLatin1Char(' ')); @@ -511,7 +536,8 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type) } case Type::Double: { - QString string = QString::number(Common::BitCast(accessors->ReadU64(address)), 'g', 4); + QString string = + QString::number(Common::BitCast(accessors->ReadU64(guard, address)), 'g', 4); // Align to first digit. if (!string.startsWith(QLatin1Char('-'))) string.prepend(QLatin1Char(' ')); @@ -519,7 +545,7 @@ QString MemoryViewWidget::ValueToString(u32 address, Type type) return string; } default: - return QStringLiteral("-"); + return INVALID_MEMORY; } } @@ -823,7 +849,11 @@ void MemoryViewWidget::OnCopyHex(u32 addr) const auto length = GetTypeSize(m_type); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); - u64 value = accessors->ReadU64(addr); + + const u64 value = [addr, accessors] { + Core::CPUThreadGuard guard; + return accessors->ReadU64(guard, addr); + }(); QApplication::clipboard()->setText( QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2)); @@ -839,10 +869,14 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos) return; const u32 addr = item_selected->data(USER_ROLE_CELL_ADDRESS).toUInt(); - const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); const bool item_has_value = item_selected->data(USER_ROLE_VALUE_TYPE).toInt() != static_cast(Type::Null) && - accessors->IsValidAddress(addr); + [this, addr] { + const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); + + Core::CPUThreadGuard guard; + return accessors->IsValidAddress(guard, addr); + }(); auto* menu = new QMenu(this); diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h index 19cd2dd85b..e5e15f5abe 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h @@ -15,6 +15,11 @@ namespace AddressSpace enum class Type; } +namespace Core +{ +class CPUThreadGuard; +} + class MemoryViewTable; class MemoryViewWidget final : public QWidget @@ -75,9 +80,10 @@ private: void OnCopyHex(u32 addr); void UpdateBreakpointTags(); void UpdateColumns(); + void UpdateColumns(const Core::CPUThreadGuard* guard); void ScrollbarActionTriggered(int action); void ScrollbarSliderReleased(); - QString ValueToString(u32 address, Type type); + QString ValueToString(const Core::CPUThreadGuard& guard, u32 address, Type type); MemoryViewTable* m_table; QScrollBar* m_scrollbar; diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp index fc6ced4743..ab3e269470 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp @@ -495,7 +495,9 @@ void MemoryWidget::SetAddress(u32 address) { AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); - good = accessors->IsValidAddress(current_addr); + + Core::CPUThreadGuard guard; + good = accessors->IsValidAddress(guard, current_addr); } if (m_search_address->findText(current_text) == -1 && good) @@ -651,17 +653,20 @@ void MemoryWidget::OnSetValue() return; } + Core::CPUThreadGuard guard; + AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); u32 end_address = target_addr.address + static_cast(bytes.size()) - 1; - if (!accessors->IsValidAddress(target_addr.address) || !accessors->IsValidAddress(end_address)) + if (!accessors->IsValidAddress(guard, target_addr.address) || + !accessors->IsValidAddress(guard, end_address)) { ModalMessageBox::critical(this, tr("Error"), tr("Target address range is invalid.")); return; } for (const char c : bytes) - accessors->WriteU8(target_addr.address++, static_cast(c)); + accessors->WriteU8(guard, target_addr.address++, static_cast(c)); Update(); } @@ -710,8 +715,10 @@ void MemoryWidget::OnSetValueFromFile() AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); + Core::CPUThreadGuard guard; + for (u8 b : file_contents) - accessors->WriteU8(target_addr.address++, b); + accessors->WriteU8(guard, target_addr.address++, b); Update(); } @@ -822,11 +829,15 @@ void MemoryWidget::FindValue(bool next) target_addr.address += next ? 1 : -1; } - AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); + const std::optional found_addr = [&] { + AddressSpace::Accessors* accessors = + AddressSpace::GetAccessors(m_memory_view->GetAddressSpace()); - const auto found_addr = - accessors->Search(target_addr.address, reinterpret_cast(search_for.data()), - static_cast(search_for.size()), next); + Core::CPUThreadGuard guard; + return accessors->Search(guard, target_addr.address, + reinterpret_cast(search_for.data()), + static_cast(search_for.size()), next); + }(); if (found_addr.has_value()) { diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.h b/Source/Core/DolphinQt/Debugger/MemoryWidget.h index ad69f6b258..ef6be33e59 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.h @@ -20,6 +20,11 @@ class QRadioButton; class QShowEvent; class QSplitter; +namespace Core +{ +class CPUThreadGuard; +} + class MemoryWidget : public QDockWidget { Q_OBJECT diff --git a/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp b/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp index ff3c371e74..f7dd891855 100644 --- a/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp @@ -295,7 +295,11 @@ void RegisterWidget::AutoStep(const std::string& reg) const while (true) { - const AutoStepResults results = trace.AutoStepping(true); + const AutoStepResults results = [&trace] { + Core::CPUThreadGuard guard; + return trace.AutoStepping(guard, true); + }(); + emit Host::GetInstance()->UpdateDisasmDialog(); if (!results.timed_out) diff --git a/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp b/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp index 07fb8eadef..c9d0df2930 100644 --- a/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/ThreadWidget.cpp @@ -256,7 +256,9 @@ void ThreadWidget::Update() { m_thread_table->setRowCount(0); UpdateThreadContext({}); - UpdateThreadCallstack({}); + + Core::CPUThreadGuard guard; + UpdateThreadCallstack(guard, {}); } if (emu_state != Core::State::Paused) return; @@ -264,8 +266,8 @@ void ThreadWidget::Update() const auto format_hex = [](u32 value) { return QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0')); }; - const auto format_hex_from = [&format_hex](u32 addr) { - addr = PowerPC::HostIsRAMAddress(addr) ? PowerPC::HostRead_U32(addr) : 0; + const auto format_hex_from = [&format_hex](const Core::CPUThreadGuard& guard, u32 addr) { + addr = PowerPC::HostIsRAMAddress(guard, addr) ? PowerPC::HostRead_U32(guard, addr) : 0; return format_hex(addr); }; const auto get_state = [](u16 thread_state) { @@ -298,35 +300,41 @@ void ThreadWidget::Update() .arg(start, 8, 16, QLatin1Char('0')); }; - // YAGCD - Section 4.2.1.4 Dolphin OS Globals - m_current_context->setText(format_hex_from(0x800000D4)); - m_current_thread->setText(format_hex_from(0x800000E4)); - m_default_thread->setText(format_hex_from(0x800000D8)); - - m_queue_head->setText(format_hex_from(0x800000DC)); - m_queue_tail->setText(format_hex_from(0x800000E0)); - - // Thread group - m_threads = PowerPC::debug_interface.GetThreads(); - int i = 0; - m_thread_table->setRowCount(i); - for (const auto& thread : m_threads) { - m_thread_table->insertRow(i); - m_thread_table->setItem(i, 0, new QTableWidgetItem(format_hex(thread->GetAddress()))); - m_thread_table->setItem(i, 1, new QTableWidgetItem(get_state(thread->GetState()))); - m_thread_table->setItem(i, 2, new QTableWidgetItem(QString::number(thread->IsDetached()))); - m_thread_table->setItem(i, 3, new QTableWidgetItem(QString::number(thread->IsSuspended()))); - m_thread_table->setItem(i, 4, - new QTableWidgetItem(get_priority(thread->GetBasePriority(), - thread->GetEffectivePriority()))); - m_thread_table->setItem( - i, 5, new QTableWidgetItem(get_stack(thread->GetStackEnd(), thread->GetStackStart()))); - m_thread_table->setItem(i, 6, new QTableWidgetItem(QString::number(thread->GetErrno()))); - m_thread_table->setItem(i, 7, - new QTableWidgetItem(QString::fromStdString(thread->GetSpecific()))); - i += 1; + Core::CPUThreadGuard guard; + + // YAGCD - Section 4.2.1.4 Dolphin OS Globals + m_current_context->setText(format_hex_from(guard, 0x800000D4)); + m_current_thread->setText(format_hex_from(guard, 0x800000E4)); + m_default_thread->setText(format_hex_from(guard, 0x800000D8)); + + m_queue_head->setText(format_hex_from(guard, 0x800000DC)); + m_queue_tail->setText(format_hex_from(guard, 0x800000E0)); + + // Thread group + m_threads = PowerPC::debug_interface.GetThreads(guard); + + int i = 0; + m_thread_table->setRowCount(i); + for (const auto& thread : m_threads) + { + m_thread_table->insertRow(i); + m_thread_table->setItem(i, 0, new QTableWidgetItem(format_hex(thread->GetAddress()))); + m_thread_table->setItem(i, 1, new QTableWidgetItem(get_state(thread->GetState()))); + m_thread_table->setItem(i, 2, new QTableWidgetItem(QString::number(thread->IsDetached()))); + m_thread_table->setItem(i, 3, new QTableWidgetItem(QString::number(thread->IsSuspended()))); + m_thread_table->setItem(i, 4, + new QTableWidgetItem(get_priority(thread->GetBasePriority(), + thread->GetEffectivePriority()))); + m_thread_table->setItem( + i, 5, new QTableWidgetItem(get_stack(thread->GetStackEnd(), thread->GetStackStart()))); + m_thread_table->setItem(i, 6, new QTableWidgetItem(QString::number(thread->GetErrno()))); + m_thread_table->setItem( + i, 7, new QTableWidgetItem(QString::fromStdString(thread->GetSpecific(guard)))); + i += 1; + } } + m_thread_table->resizeColumnsToContents(); m_thread_table->resizeRowsToContents(); @@ -425,7 +433,8 @@ void ThreadWidget::UpdateThreadContext(const Common::Debug::PartialContext& cont m_context_table->resizeColumnsToContents(); } -void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& context) +void ThreadWidget::UpdateThreadCallstack(const Core::CPUThreadGuard& guard, + const Common::Debug::PartialContext& context) { m_callstack_table->setRowCount(0); @@ -439,13 +448,13 @@ void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& co u32 sp = context.gpr->at(1); for (int i = 0; i < 16; i++) { - if (sp == 0 || sp == 0xffffffff || !PowerPC::HostIsRAMAddress(sp)) + if (sp == 0 || sp == 0xffffffff || !PowerPC::HostIsRAMAddress(guard, sp)) break; m_callstack_table->insertRow(i); m_callstack_table->setItem(i, 0, new QTableWidgetItem(format_hex(sp))); - if (PowerPC::HostIsRAMAddress(sp + 4)) + if (PowerPC::HostIsRAMAddress(guard, sp + 4)) { - const u32 lr_save = PowerPC::HostRead_U32(sp + 4); + const u32 lr_save = PowerPC::HostRead_U32(guard, sp + 4); m_callstack_table->setItem(i, 2, new QTableWidgetItem(format_hex(lr_save))); m_callstack_table->setItem(i, 3, new QTableWidgetItem(QString::fromStdString( @@ -455,18 +464,19 @@ void ThreadWidget::UpdateThreadCallstack(const Common::Debug::PartialContext& co { m_callstack_table->setItem(i, 2, new QTableWidgetItem(QStringLiteral("--------"))); } - sp = PowerPC::HostRead_U32(sp); + sp = PowerPC::HostRead_U32(guard, sp); m_callstack_table->setItem(i, 1, new QTableWidgetItem(format_hex(sp))); } } void ThreadWidget::OnSelectionChanged(int row) { + Core::CPUThreadGuard guard; Common::Debug::PartialContext context; if (row >= 0 && size_t(row) < m_threads.size()) - context = m_threads[row]->GetContext(); + context = m_threads[row]->GetContext(guard); UpdateThreadContext(context); - UpdateThreadCallstack(context); + UpdateThreadCallstack(guard, context); } diff --git a/Source/Core/DolphinQt/Debugger/ThreadWidget.h b/Source/Core/DolphinQt/Debugger/ThreadWidget.h index 0b43cb83a2..5aedd72a4f 100644 --- a/Source/Core/DolphinQt/Debugger/ThreadWidget.h +++ b/Source/Core/DolphinQt/Debugger/ThreadWidget.h @@ -47,7 +47,8 @@ private: void Update(); void UpdateThreadContext(const Common::Debug::PartialContext& context); - void UpdateThreadCallstack(const Common::Debug::PartialContext& context); + void UpdateThreadCallstack(const Core::CPUThreadGuard& guard, + const Common::Debug::PartialContext& context); void OnSelectionChanged(int row); QGroupBox* m_state; diff --git a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp index 7dfc0afe88..e580c32b68 100644 --- a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp @@ -161,6 +161,8 @@ void WatchWidget::Update() // i18n: Floating-point (non-integer) number tr("Float"), tr("Locked")}); + Core::CPUThreadGuard guard; + for (int i = 0; i < size; i++) { const auto& entry = PowerPC::debug_interface.GetWatch(i); @@ -181,18 +183,18 @@ void WatchWidget::Update() QBrush brush = QPalette().brush(QPalette::Text); - if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(entry.address)) + if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(guard, entry.address)) brush.setColor(Qt::red); if (Core::IsRunning()) { - if (PowerPC::HostIsRAMAddress(entry.address)) + if (PowerPC::HostIsRAMAddress(guard, entry.address)) { - hex->setText(QStringLiteral("%1").arg(PowerPC::HostRead_U32(entry.address), 8, 16, + hex->setText(QStringLiteral("%1").arg(PowerPC::HostRead_U32(guard, entry.address), 8, 16, QLatin1Char('0'))); - decimal->setText(QString::number(PowerPC::HostRead_U32(entry.address))); - string->setText(QString::fromStdString(PowerPC::HostGetString(entry.address, 32))); - floatValue->setText(QString::number(PowerPC::HostRead_F32(entry.address))); + decimal->setText(QString::number(PowerPC::HostRead_U32(guard, entry.address))); + string->setText(QString::fromStdString(PowerPC::HostGetString(guard, entry.address, 32))); + floatValue->setText(QString::number(PowerPC::HostRead_F32(guard, entry.address))); lockValue->setCheckState(entry.locked ? Qt::Checked : Qt::Unchecked); } } @@ -279,11 +281,13 @@ void WatchWidget::OnLoad() return; } + Core::CPUThreadGuard guard; + if (ini.GetLines("Watches", &watches, false)) { for (const auto& watch : PowerPC::debug_interface.GetWatches()) { - PowerPC::debug_interface.UnsetPatch(watch.address); + PowerPC::debug_interface.UnsetPatch(guard, watch.address); } PowerPC::debug_interface.ClearWatches(); PowerPC::debug_interface.LoadWatchesFromStrings(watches); @@ -387,17 +391,19 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item) if (good) { + Core::CPUThreadGuard guard; + if (column == COLUMN_INDEX_ADDRESS) { const auto& watch = PowerPC::debug_interface.GetWatch(row); - PowerPC::debug_interface.UnsetPatch(watch.address); + PowerPC::debug_interface.UnsetPatch(guard, watch.address); PowerPC::debug_interface.UpdateWatchAddress(row, value); if (watch.locked) - LockWatchAddress(value); + LockWatchAddress(guard, value); } else { - PowerPC::HostWrite_U32(value, PowerPC::debug_interface.GetWatch(row).address); + PowerPC::HostWrite_U32(guard, value, PowerPC::debug_interface.GetWatch(row).address); } } else @@ -410,10 +416,11 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item) { PowerPC::debug_interface.UpdateWatchLockedState(row, item->checkState() == Qt::Checked); const auto& watch = PowerPC::debug_interface.GetWatch(row); + Core::CPUThreadGuard guard; if (watch.locked) - LockWatchAddress(watch.address); + LockWatchAddress(guard, watch.address); else - PowerPC::debug_interface.UnsetPatch(watch.address); + PowerPC::debug_interface.UnsetPatch(guard, watch.address); break; } } @@ -422,9 +429,9 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item) } } -void WatchWidget::LockWatchAddress(u32 address) +void WatchWidget::LockWatchAddress(const Core::CPUThreadGuard& guard, u32 address) { - const std::string memory_data_as_string = PowerPC::HostGetString(address, 4); + const std::string memory_data_as_string = PowerPC::HostGetString(guard, address, 4); std::vector bytes; for (const char c : memory_data_as_string) @@ -432,42 +439,48 @@ void WatchWidget::LockWatchAddress(u32 address) bytes.push_back(static_cast(c)); } - PowerPC::debug_interface.SetFramePatch(address, bytes); + PowerPC::debug_interface.SetFramePatch(guard, address, bytes); } void WatchWidget::DeleteSelectedWatches() { - std::vector row_indices; - for (const auto& index : m_table->selectionModel()->selectedRows()) { - const auto* item = m_table->item(index.row(), index.column()); - const auto row_variant = item->data(Qt::UserRole); - if (row_variant.isNull()) - continue; + Core::CPUThreadGuard guard; + std::vector row_indices; + for (const auto& index : m_table->selectionModel()->selectedRows()) + { + const auto* item = m_table->item(index.row(), index.column()); + const auto row_variant = item->data(Qt::UserRole); + if (row_variant.isNull()) + continue; - row_indices.push_back(row_variant.toInt()); - } + row_indices.push_back(row_variant.toInt()); + } - // Sort greatest to smallest, so we - // don't stomp on existing indices - std::sort(row_indices.begin(), row_indices.end(), std::greater{}); - for (const int row : row_indices) - { - DeleteWatch(row); + // Sort greatest to smallest, so we don't stomp on existing indices + std::sort(row_indices.begin(), row_indices.end(), std::greater{}); + for (const int row : row_indices) + { + DeleteWatch(guard, row); + } } Update(); } -void WatchWidget::DeleteWatch(int row) +void WatchWidget::DeleteWatch(const Core::CPUThreadGuard& guard, int row) { - PowerPC::debug_interface.UnsetPatch(PowerPC::debug_interface.GetWatch(row).address); + PowerPC::debug_interface.UnsetPatch(guard, PowerPC::debug_interface.GetWatch(row).address); PowerPC::debug_interface.RemoveWatch(row); } void WatchWidget::DeleteWatchAndUpdate(int row) { - DeleteWatch(row); + { + Core::CPUThreadGuard guard; + DeleteWatch(guard, row); + } + Update(); } @@ -489,18 +502,21 @@ void WatchWidget::AddWatch(QString name, u32 addr) void WatchWidget::LockSelectedWatches() { - for (const auto& index : m_table->selectionModel()->selectedRows()) { - const auto* item = m_table->item(index.row(), index.column()); - const auto row_variant = item->data(Qt::UserRole); - if (row_variant.isNull()) - continue; - const int row = row_variant.toInt(); - const auto& watch = PowerPC::debug_interface.GetWatch(row); - if (watch.locked) - continue; - PowerPC::debug_interface.UpdateWatchLockedState(row, true); - LockWatchAddress(watch.address); + Core::CPUThreadGuard guard; + for (const auto& index : m_table->selectionModel()->selectedRows()) + { + const auto* item = m_table->item(index.row(), index.column()); + const auto row_variant = item->data(Qt::UserRole); + if (row_variant.isNull()) + continue; + const int row = row_variant.toInt(); + const auto& watch = PowerPC::debug_interface.GetWatch(row); + if (watch.locked) + continue; + PowerPC::debug_interface.UpdateWatchLockedState(row, true); + LockWatchAddress(guard, watch.address); + } } Update(); @@ -508,18 +524,21 @@ void WatchWidget::LockSelectedWatches() void WatchWidget::UnlockSelectedWatches() { - for (const auto& index : m_table->selectionModel()->selectedRows()) { - const auto* item = m_table->item(index.row(), index.column()); - const auto row_variant = item->data(Qt::UserRole); - if (row_variant.isNull()) - continue; - const int row = row_variant.toInt(); - const auto& watch = PowerPC::debug_interface.GetWatch(row); - if (!watch.locked) - continue; - PowerPC::debug_interface.UpdateWatchLockedState(row, false); - PowerPC::debug_interface.UnsetPatch(watch.address); + Core::CPUThreadGuard guard; + for (const auto& index : m_table->selectionModel()->selectedRows()) + { + const auto* item = m_table->item(index.row(), index.column()); + const auto row_variant = item->data(Qt::UserRole); + if (row_variant.isNull()) + continue; + const int row = row_variant.toInt(); + const auto& watch = PowerPC::debug_interface.GetWatch(row); + if (!watch.locked) + continue; + PowerPC::debug_interface.UpdateWatchLockedState(row, false); + PowerPC::debug_interface.UnsetPatch(guard, watch.address); + } } Update(); diff --git a/Source/Core/DolphinQt/Debugger/WatchWidget.h b/Source/Core/DolphinQt/Debugger/WatchWidget.h index 22aefb9b0e..1e3ad76e65 100644 --- a/Source/Core/DolphinQt/Debugger/WatchWidget.h +++ b/Source/Core/DolphinQt/Debugger/WatchWidget.h @@ -14,6 +14,11 @@ class QTableWidget; class QTableWidgetItem; class QToolBar; +namespace Core +{ +class CPUThreadGuard; +}; + class WatchWidget : public QDockWidget { Q_OBJECT @@ -46,9 +51,9 @@ private: void ShowContextMenu(); void OnItemChanged(QTableWidgetItem* item); - void LockWatchAddress(u32 address); + void LockWatchAddress(const Core::CPUThreadGuard& guard, u32 address); void DeleteSelectedWatches(); - void DeleteWatch(int row); + void DeleteWatch(const Core::CPUThreadGuard& guard, int row); void DeleteWatchAndUpdate(int row); void AddWatchBreakpoint(int row); void ShowInMemory(int row); diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 2fefeaf6b9..443d848740 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -1186,25 +1186,29 @@ void MenuBar::ClearSymbols() void MenuBar::GenerateSymbolsFromAddress() { + Core::CPUThreadGuard guard; + auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); - PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR, + PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR, Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); emit NotifySymbolsUpdated(); } void MenuBar::GenerateSymbolsFromSignatureDB() { + Core::CPUThreadGuard guard; + auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); - PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR, + PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR, Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); SignatureDB db(SignatureDB::HandlerType::DSY); if (db.Load(File::GetSysDirectory() + TOTALDB)) { - db.Apply(&g_symbolDB); + db.Apply(guard, &g_symbolDB); ModalMessageBox::information( this, tr("Information"), tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB))); @@ -1240,10 +1244,12 @@ void MenuBar::GenerateSymbolsFromRSO() return; } + Core::CPUThreadGuard guard; + RSOChainView rso_chain; - if (rso_chain.Load(static_cast(address))) + if (rso_chain.Load(guard, static_cast(address))) { - rso_chain.Apply(&g_symbolDB); + rso_chain.Apply(guard, &g_symbolDB); emit NotifySymbolsUpdated(); } else @@ -1293,9 +1299,12 @@ void MenuBar::GenerateSymbolsFromRSOAuto() RSOChainView rso_chain; const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16); - if (rso_chain.Load(address)) + + Core::CPUThreadGuard guard; + + if (rso_chain.Load(guard, address)) { - rso_chain.Apply(&g_symbolDB); + rso_chain.Apply(guard, &g_symbolDB); emit NotifySymbolsUpdated(); } else @@ -1306,6 +1315,8 @@ void MenuBar::GenerateSymbolsFromRSOAuto() RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) { + Core::CPUThreadGuard guard; + constexpr std::array search_for = {".elf", ".plf"}; const AddressSpace::Accessors* accessors = @@ -1324,8 +1335,8 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) return matches; } - auto found_addr = - accessors->Search(next, reinterpret_cast(str.data()), str.size() + 1, true); + auto found_addr = accessors->Search(guard, next, reinterpret_cast(str.data()), + str.size() + 1, true); if (!found_addr.has_value()) break; @@ -1334,13 +1345,13 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) // Non-null data can precede the module name. // Get the maximum name length that a module could have. - auto get_max_module_name_len = [found_addr] { + auto get_max_module_name_len = [&guard, found_addr] { constexpr u32 MODULE_NAME_MAX_LENGTH = 260; u32 len = 0; for (; len < MODULE_NAME_MAX_LENGTH; ++len) { - const auto res = PowerPC::HostRead_U8(*found_addr - (len + 1)); + const auto res = PowerPC::HostRead_U8(guard, *found_addr - (len + 1)); if (!std::isprint(res)) { break; @@ -1375,12 +1386,12 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) // Get the field (Module Name Offset) that point to the string const auto module_name_offset_addr = - accessors->Search(lookup_addr, ref.data(), ref.size(), false); + accessors->Search(guard, lookup_addr, ref.data(), ref.size(), false); if (!module_name_offset_addr.has_value()) continue; // The next 4 bytes should be the module name length - module_name_length = accessors->ReadU32(*module_name_offset_addr + 4); + module_name_length = accessors->ReadU32(guard, *module_name_offset_addr + 4); if (module_name_length == max_name_length - i + str.length()) { found_addr = module_name_offset_addr; @@ -1392,11 +1403,11 @@ RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress) if (!found) continue; - const auto module_name_offset = accessors->ReadU32(*found_addr); + const auto module_name_offset = accessors->ReadU32(guard, *found_addr); // Go to the beginning of the RSO header matches.emplace_back(*found_addr - 16, - PowerPC::HostGetString(module_name_offset, module_name_length)); + PowerPC::HostGetString(guard, module_name_offset, module_name_length)); progress.SetLabelText(tr("Modules found: %1").arg(matches.size())); } @@ -1416,11 +1427,16 @@ void MenuBar::LoadSymbolMap() if (!map_exists) { g_symbolDB.Clear(); - PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR + 0x1300000, - Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); - SignatureDB db(SignatureDB::HandlerType::DSY); - if (db.Load(File::GetSysDirectory() + TOTALDB)) - db.Apply(&g_symbolDB); + + { + Core::CPUThreadGuard guard; + + PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR + 0x1300000, + Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB); + SignatureDB db(SignatureDB::HandlerType::DSY); + if (db.Load(File::GetSysDirectory() + TOTALDB)) + db.Apply(guard, &g_symbolDB); + } ModalMessageBox::warning(this, tr("Warning"), tr("'%1' not found, scanning for common functions instead") @@ -1505,7 +1521,13 @@ void MenuBar::SaveCode() const std::string path = writable_map_file.substr(0, writable_map_file.find_last_of('.')) + "_code.map"; - if (!g_symbolDB.SaveCodeMap(path)) + bool success; + { + Core::CPUThreadGuard guard; + success = g_symbolDB.SaveCodeMap(guard, path); + } + + if (!success) { ModalMessageBox::warning( this, tr("Error"), @@ -1515,7 +1537,9 @@ void MenuBar::SaveCode() bool MenuBar::TryLoadMapFile(const QString& path, const bool bad) { - if (!g_symbolDB.LoadMap(path.toStdString(), bad)) + Core::CPUThreadGuard guard; + + if (!g_symbolDB.LoadMap(guard, path.toStdString(), bad)) { ModalMessageBox::warning(this, tr("Error"), tr("Failed to load map file '%1'").arg(path)); return false; @@ -1596,7 +1620,10 @@ void MenuBar::ApplySignatureFile() const std::string load_path = file.toStdString(); SignatureDB db(load_path); db.Load(load_path); - db.Apply(&g_symbolDB); + { + Core::CPUThreadGuard guard; + db.Apply(guard, &g_symbolDB); + } db.List(); auto& system = Core::System::GetInstance(); HLE::PatchFunctions(system); @@ -1665,12 +1692,14 @@ void MenuBar::SearchInstruction() auto& system = Core::System::GetInstance(); auto& memory = system.GetMemory(); + Core::CPUThreadGuard guard; + bool found = false; for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(); addr += 4) { const auto ins_name = - QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr))); + QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(guard, addr))); if (op == ins_name) { NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr); From 6f0266e8deb9b9d46fb6f291db696fed06c1bed0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 12 Feb 2023 12:50:28 +0100 Subject: [PATCH 2/2] DolphinQt: Only update call stack if paused This avoids a pseudo infinite loop where CodeWidget::UpdateCallstack would lock the CPU in order to read the call stack, causing the CPU to call Host_UpdateDisasmDialog because it's transitioning from running to pausing, causing Host::UpdateDisasmDialog to be emitted, causing CodeWidget::Update to be called, once again causing CodeWidget::UpdateCallstack to be called, repeating the cycle. Dolphin didn't go completely unresponsive during this, because Host_UpdateDisasmDialog schedules the emitting of Host::UpdateDisasmDialog to happen on another thread without blocking, but it was stopping certain operations like exiting emulation from working. --- Source/Core/DolphinQt/Debugger/CodeWidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp index 513a68672d..391152abc9 100644 --- a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp @@ -322,11 +322,11 @@ void CodeWidget::Update() void CodeWidget::UpdateCallstack() { - if (Core::GetState() == Core::State::Starting) - return; - m_callstack_list->clear(); + if (Core::GetState() != Core::State::Paused) + return; + std::vector stack; const bool success = [&stack] {