From c9ad4ec68d0a015ade1d7a09dccc06d517c22df8 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Mon, 4 Dec 2023 14:10:04 +0000 Subject: [PATCH] Riivolution: add search_count attribute to memory patches This allows you to write a single memory search patch that gets applied multiple times at different offsets. Note that for implementation simplicity this count currently resets for each DOL section. This is also the existing behavior for single-match patches. --- Source/Core/DiscIO/RiivolutionParser.cpp | 1 + Source/Core/DiscIO/RiivolutionParser.h | 5 ++++- Source/Core/DiscIO/RiivolutionPatcher.cpp | 10 +++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Core/DiscIO/RiivolutionParser.cpp b/Source/Core/DiscIO/RiivolutionParser.cpp index f120335f56..98ea299b13 100644 --- a/Source/Core/DiscIO/RiivolutionParser.cpp +++ b/Source/Core/DiscIO/RiivolutionParser.cpp @@ -211,6 +211,7 @@ std::optional ParseString(std::string_view xml, std::string xml_path) memory.m_original = ReadHexString(patch_subnode.attribute("original").as_string()); memory.m_ocarina = patch_subnode.attribute("ocarina").as_bool(false); memory.m_search = patch_subnode.attribute("search").as_bool(false); + memory.m_search_count = patch_subnode.attribute("search_count").as_uint(1); memory.m_align = patch_subnode.attribute("align").as_uint(1); } } diff --git a/Source/Core/DiscIO/RiivolutionParser.h b/Source/Core/DiscIO/RiivolutionParser.h index a52cb8f7cc..a2d4486cca 100644 --- a/Source/Core/DiscIO/RiivolutionParser.h +++ b/Source/Core/DiscIO/RiivolutionParser.h @@ -146,9 +146,12 @@ struct Memory bool m_ocarina = false; // If true, the offset is not known, and instead we should search for the m_original bytes in - // memory and replace them where found. Only searches in MEM1, and only replaces the first match. + // memory and replace them where found. Only searches in MEM1. bool m_search = false; + // For m_search. Replaces up to m_search_count occurrences. + u32 m_search_count = 1; + // For m_search. The byte stride between search points. u32 m_align = 1; }; diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 8c54968c35..6292452797 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -565,17 +565,21 @@ static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& pat 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) + if (memory_patch.m_original.empty() || memory_patch.m_align == 0 || memory_patch.m_search_count == 0) return; const u32 stride = memory_patch.m_align; + u32 times = memory_patch.m_search_count; for (u32 i = 0; i < length - (stride - 1); i += stride) { const u32 address = ram_start + i; if (MemoryMatchesAt(guard, address, memory_patch.m_original)) { - ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch), {}); - break; + const std::vector value = GetMemoryPatchValue(patch, memory_patch); + INFO_LOG_FMT(BOOT, "Applying memory patch at [0x{:08X}, 0x{:08X})", address, address + value.size()); + ApplyMemoryPatch(guard, address, value, {}); + if (--times == 0) + break; } } }