mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #11554 from JosJuice/host-lock-cpu
DolphinQt: Properly lock CPU before accessing emulated memory
This commit is contained in:
@ -477,30 +477,31 @@ void ApplyPatchesToFiles(const std::vector<Patch>& patches, PatchIndex index,
|
||||
}
|
||||
}
|
||||
|
||||
static bool MemoryMatchesAt(u32 offset, const std::vector<u8>& value)
|
||||
static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset,
|
||||
const std::vector<u8>& 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<u8>& value,
|
||||
const std::vector<u8>& original)
|
||||
static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset,
|
||||
const std::vector<u8>& value, const std::vector<u8>& 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<u32>(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<u8> 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<Patch>& patches)
|
||||
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& system_memory = system.GetMemory();
|
||||
@ -597,14 +599,15 @@ void ApplyGeneralMemoryPatches(const std::vector<Patch>& 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<Patch>& patches, u32 ram_address, u32 ram_length)
|
||||
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard,
|
||||
const std::vector<Patch>& patches, u32 ram_address, u32 ram_length)
|
||||
{
|
||||
for (const auto& patch : patches)
|
||||
{
|
||||
@ -614,9 +617,9 @@ void ApplyApploaderMemoryPatches(const std::vector<Patch>& 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Patch>& patches, PatchIndex index,
|
||||
std::vector<DiscIO::FSTBuilderNode>* fst,
|
||||
DiscIO::FSTBuilderNode* dol_node);
|
||||
void ApplyGeneralMemoryPatches(const std::vector<Patch>& patches);
|
||||
void ApplyApploaderMemoryPatches(const std::vector<Patch>& patches, u32 ram_address,
|
||||
void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard,
|
||||
const std::vector<Patch>& patches);
|
||||
void ApplyApploaderMemoryPatches(const Core::CPUThreadGuard& guard,
|
||||
const std::vector<Patch>& patches, u32 ram_address,
|
||||
u32 ram_length);
|
||||
std::optional<SavegameRedirect>
|
||||
ExtractSavegameRedirect(const std::vector<Patch>& riivolution_patches);
|
||||
|
Reference in New Issue
Block a user