PPU: Add new patch function for SONIC 06

This commit is contained in:
Eladash 2022-11-19 13:50:31 +02:00 committed by Ivan
parent 681a6ef73c
commit f572e29a13
10 changed files with 94 additions and 25 deletions

View File

@ -718,7 +718,7 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
// Always executable // Always executable
u64 flags = vm::alloc_executable | vm::alloc_unwritable; u64 flags = vm::alloc_executable | vm::alloc_unwritable;
switch (p.offset % patch_engine::mem_protection::mask) switch (p.offset & patch_engine::mem_protection::mask)
{ {
case patch_engine::mem_protection::rw: case patch_engine::mem_protection::rw:
case patch_engine::mem_protection::wx: case patch_engine::mem_protection::wx:
@ -754,15 +754,26 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
// Register code // Register code
ppu_register_range(addr, alloc_size); ppu_register_range(addr, alloc_size);
// Write branch to code
ppu_form_branch_to_code(out_branch, addr);
resval = out_branch & -4; resval = out_branch & -4;
// Write branch to return to code
if (!ppu_form_branch_to_code(addr + static_cast<u32>(p.value.long_value) * 4, resval + 4))
{
patch_log.error("Failed to write return jump at 0x%x", addr + static_cast<u32>(p.value.long_value) * 4);
ensure(alloc_map->dealloc(addr));
continue;
}
// Write branch to code
if (!ppu_form_branch_to_code(out_branch, addr))
{
patch_log.error("Failed to jump to code cave at 0x%x", out_branch);
ensure(alloc_map->dealloc(addr));
continue;
}
// Write address of the allocated memory to the code entry // Write address of the allocated memory to the code entry
*vm::get_super_ptr<u32>(resval) = addr; *vm::get_super_ptr<u32>(resval) = addr;
// Write branch to return to code
ppu_form_branch_to_code(addr + static_cast<u32>(p.value.long_value) * 4, resval + 4);
relocate_instructions_at = addr; relocate_instructions_at = addr;
break; break;
} }

View File

@ -322,6 +322,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/cellVoice.cpp Cell/Modules/cellVoice.cpp
Cell/Modules/cellVpost.cpp Cell/Modules/cellVpost.cpp
Cell/Modules/cellWebBrowser.cpp Cell/Modules/cellWebBrowser.cpp
Cell/Modules/HLE_PATCHES.cpp
Cell/Modules/libad_async.cpp Cell/Modules/libad_async.cpp
Cell/Modules/libad_core.cpp Cell/Modules/libad_core.cpp
Cell/Modules/libmedi.cpp Cell/Modules/libmedi.cpp

View File

@ -0,0 +1,58 @@
#include "stdafx.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "Utilities/Thread.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include <thread>
// SONIC THE HEDGEDOG: a fix for a race condition between SPUs and PPUs causing missing graphics (SNR is overriden when non-empty)
void WaitForSPUsToEmptySNRs(ppu_thread& ppu, u32 spu_id, u32 snr_mask)
{
ppu.state += cpu_flag::wait;
auto [spu, group] = lv2_spu_group::get_thread(spu_id);
if ((!spu && spu_id != umax) || snr_mask % 4 == 0)
{
return;
}
// Wait until specified SNRs are reported empty at least once
for (bool has_busy = true; has_busy && !ppu.is_stopped(); std::this_thread::yield())
{
has_busy = false;
auto for_one = [&](u32, spu_thread& spu)
{
if ((snr_mask & 1) && spu.ch_snr1.get_count())
{
has_busy = true;
return;
}
if ((snr_mask & 2) && spu.ch_snr2.get_count())
{
has_busy = true;
}
};
if (spu)
{
// Wait for a single SPU
for_one(spu->id, *spu);
}
else
{
// Wait for all SPUs
idm::select<named_thread<spu_thread>>(for_one);
}
}
}
DECLARE(ppu_module_manager::hle_patches)("RPCS3_HLE_LIBRARY", []()
{
REG_FUNC(RPCS3_HLE_LIBRARY, WaitForSPUsToEmptySNRs);
});

View File

@ -163,7 +163,7 @@ bool statichle_handler::check_against_patterns(vm::cptr<u8>& data, u32 size, u32
} }
const auto sfunc = &::at32(smodule->functions, pat.fnid); const auto sfunc = &::at32(smodule->functions, pat.fnid);
const u32 target = g_fxo->get<ppu_function_manager>().func_addr(sfunc->index) + 4; const u32 target = g_fxo->get<ppu_function_manager>().func_addr(sfunc->index, true);
// write stub // write stub
vm::write32(addr, ppu_instructions::LIS(0, (target&0xFFFF0000)>>16)); vm::write32(addr, ppu_instructions::LIS(0, (target&0xFFFF0000)>>16));

View File

@ -290,14 +290,14 @@ public:
return access(llvm); return access(llvm);
} }
u32 func_addr(u32 index) const u32 func_addr(u32 index, bool is_code_addr = false) const
{ {
if (index >= access().size() || !addr) if (index >= access().size() || !addr)
{ {
return 0; return 0;
} }
return addr + index * 8; return addr + index * 8 + (is_code_addr ? 4 : 0);
} }
// Allocation address // Allocation address

View File

@ -153,7 +153,7 @@ struct ppu_linkage_info
// Module map // Module map
std::map<std::string, module_data> modules{}; std::map<std::string, module_data> modules{};
std::map<std::string, std::shared_ptr<atomic_t<bool>>, std::less<>> lib_lock; std::map<std::string, atomic_t<bool>, std::less<>> lib_lock;
shared_mutex mutex; shared_mutex mutex;
}; };
@ -278,6 +278,7 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
&ppu_module_manager::sys_libc, &ppu_module_manager::sys_libc,
&ppu_module_manager::sys_lv2dbg, &ppu_module_manager::sys_lv2dbg,
&ppu_module_manager::static_hle, &ppu_module_manager::static_hle,
&ppu_module_manager::hle_patches,
}; };
// Initialize double-purpose fake OPD array for HLE functions // Initialize double-purpose fake OPD array for HLE functions
@ -640,9 +641,9 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib)
reader_lock lock(link->mutex); reader_lock lock(link->mutex);
if (auto it = std::as_const(link->lib_lock).find(libname); it != link->lib_lock.cend() && it->second) if (auto it = link->lib_lock.find(libname); it != link->lib_lock.cend())
{ {
return lock_lib ? !it->second->test_and_set() : it->second->test_and_reset(); return lock_lib ? !it->second.test_and_set() : it->second.test_and_reset();
} }
if (!lock_lib) if (!lock_lib)
@ -653,15 +654,9 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib)
lock.upgrade(); lock.upgrade();
auto& lib_lock = link->lib_lock.emplace(std::string{libname}, nullptr).first->second; auto& lib_lock = link->lib_lock.emplace(std::string{libname}, false).first->second;
if (!lib_lock) return !lib_lock.test_and_set();
{
lib_lock = std::make_shared<atomic_t<bool>>(true);
return true;
}
return !lib_lock->test_and_set();
} }
// Load and register exports; return special exports found (nameless module) // Load and register exports; return special exports found (nameless module)
@ -750,7 +745,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
if (_sf && (_sf->flags & MFF_FORCED_HLE)) if (_sf && (_sf->flags & MFF_FORCED_HLE))
{ {
// Inject a branch to the HLE implementation // Inject a branch to the HLE implementation
const u32 target = g_fxo->get<ppu_function_manager>().func_addr(_sf->index) + 4; const u32 target = g_fxo->get<ppu_function_manager>().func_addr(_sf->index, true);
// Set exported function // Set exported function
flink.export_addr = target - 4; flink.export_addr = target - 4;

View File

@ -80,9 +80,9 @@ public:
std::unordered_map<u32, ppu_static_function, value_hash<u32>> functions{}; std::unordered_map<u32, ppu_static_function, value_hash<u32>> functions{};
std::unordered_map<u32, ppu_static_variable, value_hash<u32>> variables{}; std::unordered_map<u32, ppu_static_variable, value_hash<u32>> variables{};
public:
ppu_static_module(const char* name); ppu_static_module(const char* name);
public:
ppu_static_module(const char* name, void(*init)()) ppu_static_module(const char* name, void(*init)())
: ppu_static_module(name) : ppu_static_module(name)
{ {
@ -278,6 +278,7 @@ public:
static const ppu_static_module sys_libc; static const ppu_static_module sys_libc;
static const ppu_static_module sys_lv2dbg; static const ppu_static_module sys_lv2dbg;
static const ppu_static_module static_hle; static const ppu_static_module static_hle;
static const ppu_static_module hle_patches;
private: private:
inline static std::unordered_map<std::string, ppu_static_module*> s_module_map; inline static std::unordered_map<std::string, ppu_static_module*> s_module_map;

View File

@ -667,7 +667,7 @@ struct ppu_far_jumps_t
// NOTE: In order to clean up this information all calls must return in order // NOTE: In order to clean up this information all calls must return in order
auto& saved_info = calls_info.emplace_back(); auto& saved_info = calls_info.emplace_back();
saved_info.cia = pc; saved_info.cia = pc;
saved_info.saved_lr = std::exchange(ppu->lr, FIND_FUNC(ppu_return_from_far_jump)); saved_info.saved_lr = std::exchange(ppu->lr, g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(ppu_return_from_far_jump), true));
saved_info.saved_r2 = std::exchange(ppu->gpr[2], opd.rtoc); saved_info.saved_r2 = std::exchange(ppu->gpr[2], opd.rtoc);
} }
@ -1243,7 +1243,7 @@ std::vector<std::pair<u32, u32>> ppu_thread::dump_callstack_list() const
} }
// Ignore HLE stop address // Ignore HLE stop address
return addr == g_fxo->get<ppu_function_manager>().func_addr(1) + 4; return addr == g_fxo->get<ppu_function_manager>().func_addr(1, true);
}; };
if (is_invalid(addr)) if (is_invalid(addr))
@ -1921,7 +1921,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
interrupt_thread_executing = true; interrupt_thread_executing = true;
cia = addr; cia = addr;
gpr[2] = rtoc; gpr[2] = rtoc;
lr = g_fxo->get<ppu_function_manager>().func_addr(1) + 4; // HLE stop address lr = g_fxo->get<ppu_function_manager>().func_addr(1, true); // HLE stop address
current_function = nullptr; current_function = nullptr;
if (std::exchange(loaded_from_savestate, false)) if (std::exchange(loaded_from_savestate, false))

View File

@ -66,6 +66,7 @@
<ClCompile Include="Emu\Cell\Modules\cellMusicSelectionContext.cpp" /> <ClCompile Include="Emu\Cell\Modules\cellMusicSelectionContext.cpp" />
<ClCompile Include="Emu\Cell\Modules\libfs_utility_init.cpp" /> <ClCompile Include="Emu\Cell\Modules\libfs_utility_init.cpp" />
<ClCompile Include="Emu\Cell\Modules\sys_crashdump.cpp" /> <ClCompile Include="Emu\Cell\Modules\sys_crashdump.cpp" />
<ClCompile Include="Emu\Cell\Modules\HLE_PATCHES.cpp" />
<ClCompile Include="Emu\Io\camera_config.cpp" /> <ClCompile Include="Emu\Io\camera_config.cpp" />
<ClCompile Include="Emu\Io\recording_config.cpp" /> <ClCompile Include="Emu\Io\recording_config.cpp" />
<ClCompile Include="Emu\Io\Turntable.cpp" /> <ClCompile Include="Emu\Io\Turntable.cpp" />

View File

@ -1101,6 +1101,8 @@
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Io\recording_config.cpp"> <ClCompile Include="Emu\Io\recording_config.cpp">
<Filter>Emu\Io</Filter> <Filter>Emu\Io</Filter>
<ClCompile Include="Emu\Cell\Modules\HLE_PATCHES.cpp">
<Filter>Emu\Cell\Modules</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>