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
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::wx:
@ -754,15 +754,26 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
// Register code
ppu_register_range(addr, alloc_size);
// Write branch to code
ppu_form_branch_to_code(out_branch, addr);
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
*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;
break;
}

View File

@ -322,6 +322,7 @@ target_sources(rpcs3_emu PRIVATE
Cell/Modules/cellVoice.cpp
Cell/Modules/cellVpost.cpp
Cell/Modules/cellWebBrowser.cpp
Cell/Modules/HLE_PATCHES.cpp
Cell/Modules/libad_async.cpp
Cell/Modules/libad_core.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 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
vm::write32(addr, ppu_instructions::LIS(0, (target&0xFFFF0000)>>16));

View File

@ -290,14 +290,14 @@ public:
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)
{
return 0;
}
return addr + index * 8;
return addr + index * 8 + (is_code_addr ? 4 : 0);
}
// Allocation address

View File

@ -153,7 +153,7 @@ struct ppu_linkage_info
// Module map
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;
};
@ -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_lv2dbg,
&ppu_module_manager::static_hle,
&ppu_module_manager::hle_patches,
};
// 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);
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)
@ -653,15 +654,9 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib)
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)
{
lib_lock = std::make_shared<atomic_t<bool>>(true);
return true;
}
return !lib_lock->test_and_set();
return !lib_lock.test_and_set();
}
// 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))
{
// 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
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_variable, value_hash<u32>> variables{};
public:
ppu_static_module(const char* name);
public:
ppu_static_module(const char* name, void(*init)())
: ppu_static_module(name)
{
@ -278,6 +278,7 @@ public:
static const ppu_static_module sys_libc;
static const ppu_static_module sys_lv2dbg;
static const ppu_static_module static_hle;
static const ppu_static_module hle_patches;
private:
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
auto& saved_info = calls_info.emplace_back();
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);
}
@ -1243,7 +1243,7 @@ std::vector<std::pair<u32, u32>> ppu_thread::dump_callstack_list() const
}
// 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))
@ -1921,7 +1921,7 @@ void ppu_thread::fast_call(u32 addr, u64 rtoc)
interrupt_thread_executing = true;
cia = addr;
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;
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\libfs_utility_init.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\recording_config.cpp" />
<ClCompile Include="Emu\Io\Turntable.cpp" />

View File

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