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..391152abc9 100644 --- a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp @@ -322,14 +322,17 @@ 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; - 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);