diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index a67609a592..df7cf9014f 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -450,7 +450,10 @@ bool CBoot::BootUp(std::unique_ptr boot) struct BootTitle { - BootTitle() : config(SConfig::GetInstance()) {} + BootTitle(const std::vector& patches) + : config(SConfig::GetInstance()), riivolution_patches(patches) + { + } bool operator()(BootParameters::Disc& disc) const { NOTICE_LOG_FMT(BOOT, "Booting from disc: {}", disc.path); @@ -460,7 +463,7 @@ bool CBoot::BootUp(std::unique_ptr boot) if (!volume) return false; - if (!EmulatedBS2(config.bWii, *volume)) + if (!EmulatedBS2(config.bWii, *volume, riivolution_patches)) return false; SConfig::OnNewTitleLoad(); @@ -570,12 +573,13 @@ bool CBoot::BootUp(std::unique_ptr boot) private: const SConfig& config; + const std::vector& riivolution_patches; }; - if (!std::visit(BootTitle(), boot->parameters)) + if (!std::visit(BootTitle(boot->riivolution_patches), boot->parameters)) return false; - DiscIO::Riivolution::ApplyPatchesToMemory(boot->riivolution_patches); + DiscIO::Riivolution::ApplyGeneralMemoryPatches(boot->riivolution_patches); return true; } diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 410b408b44..d9a891966b 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -115,10 +115,14 @@ private: static void SetupMSR(); static void SetupBAT(bool is_wii); - static bool RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume); - static bool EmulatedBS2_GC(const DiscIO::VolumeDisc& volume); - static bool EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume); - static bool EmulatedBS2(bool is_wii, const DiscIO::VolumeDisc& volume); + static bool RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches); + static bool EmulatedBS2_GC(const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches); + static bool EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches); + static bool EmulatedBS2(bool is_wii, const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches); static bool Load_BS2(const std::string& boot_rom_filename); static void SetupGCMemory(); diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 556c2389c8..4a533cd6ed 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -33,6 +33,7 @@ #include "Core/PowerPC/PowerPC.h" #include "DiscIO/Enums.h" +#include "DiscIO/RiivolutionPatcher.h" #include "DiscIO/VolumeDisc.h" namespace @@ -87,7 +88,8 @@ void CBoot::SetupBAT(bool is_wii) PowerPC::IBATUpdated(); } -bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume) +bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches) { const DiscIO::Partition partition = volume.GetGamePartition(); @@ -148,6 +150,8 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::VolumeDisc& volume) ram_address, length); DVDRead(volume, dvd_offset, ram_address, length, partition); + DiscIO::Riivolution::ApplyApploaderMemoryPatches(riivolution_patches, ram_address, length); + PowerPC::ppcState.gpr[3] = 0x81300004; PowerPC::ppcState.gpr[4] = 0x81300008; PowerPC::ppcState.gpr[5] = 0x8130000c; @@ -203,7 +207,8 @@ void CBoot::SetupGCMemory() // GameCube Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader, function by function, using the above utility. -bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume) +bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches) { INFO_LOG_FMT(BOOT, "Faking GC BS2..."); @@ -240,7 +245,7 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume) // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) PowerPC::ppcState.gpr[13] = ntsc ? 0x81465320 : 0x814b4fc0; - return RunApploader(/*is_wii*/ false, volume); + return RunApploader(/*is_wii*/ false, volume, riivolution_patches); } static DiscIO::Region CodeRegion(char c) @@ -436,7 +441,8 @@ static void WriteEmptyPlayRecord() // Wii Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader -bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume) +bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches) { INFO_LOG_FMT(BOOT, "Faking Wii BS2..."); if (volume.GetVolumeType() != DiscIO::Platform::WiiDisc) @@ -493,7 +499,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume) PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer - if (!RunApploader(/*is_wii*/ true, volume)) + if (!RunApploader(/*is_wii*/ true, volume, riivolution_patches)) return false; // The Apploader probably just overwrote values needed for RAM Override. Run this again! @@ -508,7 +514,9 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume) // 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(bool is_wii, const DiscIO::VolumeDisc& volume) +bool CBoot::EmulatedBS2(bool is_wii, const DiscIO::VolumeDisc& volume, + const std::vector& riivolution_patches) { - return is_wii ? EmulatedBS2_Wii(volume) : EmulatedBS2_GC(volume); + return is_wii ? EmulatedBS2_Wii(volume, riivolution_patches) : + EmulatedBS2_GC(volume, riivolution_patches); } diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 3f3a1f876f..aefa4950b9 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -527,20 +527,23 @@ static std::vector GetMemoryPatchValue(const Patch& patch, const Memory& mem static void ApplyMemoryPatch(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); } -static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patch) +static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, + u32 length) { - if (memory_patch.m_original.empty()) + if (memory_patch.m_original.empty() || memory_patch.m_align == 0) return; - const u32 ram_size = ::Memory::GetRamSize(); - const u32 stride = memory_patch.m_align < 1 ? 1 : memory_patch.m_align; - for (u32 i = 0; i < ram_size - (stride - 1); i += stride) + const u32 stride = memory_patch.m_align; + for (u32 i = 0; i < length - (stride - 1); i += stride) { - const u32 address = i | 0x80000000; + const u32 address = ram_start + i; if (MemoryMatchesAt(address, memory_patch.m_original)) { ApplyMemoryPatch(address, GetMemoryPatchValue(patch, memory_patch), {}); @@ -549,22 +552,25 @@ static void ApplySearchMemoryPatch(const Patch& patch, const Memory& memory_patc } } -static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_patch) +static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_patch, u32 ram_start, + u32 length) { - if (memory_patch.m_value.empty()) + if (memory_patch.m_offset == 0) + return; + const std::vector value = GetMemoryPatchValue(patch, memory_patch); + if (value.empty()) return; - const u32 ram_size = ::Memory::GetRamSize(); - for (u32 i = 0; i < ram_size; i += 4) + for (u32 i = 0; i < length; i += 4) { // first find the pattern - const u32 address = i | 0x80000000; - if (MemoryMatchesAt(address, memory_patch.m_value)) + const u32 address = ram_start + i; + if (MemoryMatchesAt(address, value)) { - for (; i < ram_size; i += 4) + for (; i < length; i += 4) { // from the pattern find the next blr instruction - const u32 blr_address = i | 0x80000000; + const u32 blr_address = ram_start + i; auto blr = PowerPC::HostTryReadU32(blr_address); if (blr && blr->value == 0x4e800020) { @@ -580,22 +586,40 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat } } -void ApplyPatchesToMemory(const std::vector& patches) +void ApplyGeneralMemoryPatches(const std::vector& patches) { for (const auto& patch : patches) { for (const auto& memory : patch.m_memory_patches) { if (memory.m_ocarina) - ApplyOcarinaMemoryPatch(patch, memory); - else if (memory.m_search) - ApplySearchMemoryPatch(patch, memory); + continue; + + if (memory.m_search) + ApplySearchMemoryPatch(patch, memory, 0x80000000, ::Memory::GetRamSize()); else ApplyMemoryPatch(patch, memory); } } } +void ApplyApploaderMemoryPatches(const std::vector& patches, u32 ram_address, u32 ram_length) +{ + for (const auto& patch : patches) + { + for (const auto& memory : patch.m_memory_patches) + { + if (!memory.m_ocarina && !memory.m_search) + continue; + + if (memory.m_ocarina) + ApplyOcarinaMemoryPatch(patch, memory, ram_address, ram_length); + else + ApplySearchMemoryPatch(patch, memory, ram_address, ram_length); + } + } +} + std::optional ExtractSavegameRedirect(const std::vector& riivolution_patches) { diff --git a/Source/Core/DiscIO/RiivolutionPatcher.h b/Source/Core/DiscIO/RiivolutionPatcher.h index e93ae5c00e..0f3de33caf 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.h +++ b/Source/Core/DiscIO/RiivolutionPatcher.h @@ -68,7 +68,9 @@ private: void ApplyPatchesToFiles(const std::vector& patches, std::vector* fst, DiscIO::FSTBuilderNode* dol_node); -void ApplyPatchesToMemory(const std::vector& patches); +void ApplyGeneralMemoryPatches(const std::vector& patches); +void ApplyApploaderMemoryPatches(const std::vector& patches, u32 ram_address, + u32 ram_length); std::optional ExtractSavegameRedirect(const std::vector& riivolution_patches); } // namespace DiscIO::Riivolution