Patches/PPU: Add jump_link patch type

This commit is contained in:
Eladash 2021-09-02 18:14:26 +03:00 committed by Ivan
parent fafefb2cf5
commit f98595bee5
5 changed files with 28 additions and 18 deletions

View File

@ -40,6 +40,7 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
case patch_type::alloc: return "alloc"; case patch_type::alloc: return "alloc";
case patch_type::code_alloc: return "calloc"; case patch_type::code_alloc: return "calloc";
case patch_type::jump: return "jump"; case patch_type::jump: return "jump";
case patch_type::jump_link: return "jumpl";
case patch_type::load: return "load"; case patch_type::load: return "load";
case patch_type::byte: return "byte"; case patch_type::byte: return "byte";
case patch_type::le16: return "le16"; case patch_type::le16: return "le16";
@ -551,7 +552,7 @@ void patch_engine::append_title_patches(const std::string& title_id)
} }
void ppu_register_range(u32 addr, u32 size); void ppu_register_range(u32 addr, u32 size);
bool ppu_form_branch_to_code(u32 entry, u32 target); bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false);
void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr) void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
{ {
@ -737,12 +738,13 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
break; break;
} }
case patch_type::jump: case patch_type::jump:
case patch_type::jump_link:
{ {
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first; const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
const u32 dest = static_cast<u32>(p.value.long_value); const u32 dest = static_cast<u32>(p.value.long_value);
// Allow only if points to a PPU executable instruction // Allow only if points to a PPU executable instruction
if (!ppu_form_branch_to_code(out_branch, dest)) if (!ppu_form_branch_to_code(out_branch, dest, p.type == patch_type::jump_link))
{ {
continue; continue;
} }

View File

@ -29,6 +29,7 @@ enum class patch_type
alloc, // Allocate memory at address (zeroized executable memory) alloc, // Allocate memory at address (zeroized executable memory)
code_alloc,// Allocate memory somewhere, saves branch to memory at specfied address (filled with PPU NOP and branch for returning) code_alloc,// Allocate memory somewhere, saves branch to memory at specfied address (filled with PPU NOP and branch for returning)
jump, // Install special 32-bit jump instruction (PPU only atm) jump, // Install special 32-bit jump instruction (PPU only atm)
jump_link, // jump + set link (PPU only atm)
byte, byte,
le16, le16,
le32, le32,

View File

@ -528,7 +528,7 @@ struct ppu_prx_module_info
be_t<u32> unk5; be_t<u32> unk5;
}; };
bool ppu_form_branch_to_code(u32 entry, u32 target); bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false);
// Load and register exports; return special exports found (nameless module) // Load and register exports; return special exports found (nameless module)
static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end) static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end)

View File

@ -487,11 +487,11 @@ extern void ppu_register_function_at(u32 addr, u32 size, u64 ptr)
struct ppu_far_jumps_t struct ppu_far_jumps_t
{ {
std::unordered_map<u32, u32> vals; std::unordered_map<u32, std::pair<u32, bool>> vals;
mutable shared_mutex mutex; mutable shared_mutex mutex;
u32 get_target(u32 pc) const std::pair<u32, bool> get_target(u32 pc) const
{ {
reader_lock lock(mutex); reader_lock lock(mutex);
@ -500,23 +500,25 @@ struct ppu_far_jumps_t
return it->second; return it->second;
} }
return 0; return {};
} }
}; };
u32 ppu_get_far_jump(u32 pc) u32 ppu_get_far_jump(u32 pc)
{ {
g_fxo->init<ppu_far_jumps_t>(); g_fxo->init<ppu_far_jumps_t>();
return g_fxo->get<const ppu_far_jumps_t>().get_target(pc); return g_fxo->get<const ppu_far_jumps_t>().get_target(pc).first;
} }
static bool ppu_far_jump(ppu_thread& ppu) static bool ppu_far_jump(ppu_thread& ppu)
{ {
ppu.cia = g_fxo->get<const ppu_far_jumps_t>().get_target(ppu.cia); auto [cia, link] = g_fxo->get<const ppu_far_jumps_t>().get_target(ppu.cia);
if (link) ppu.lr = ppu.cia + 4;
ppu.cia = cia;
return false; return false;
} }
bool ppu_form_branch_to_code(u32 entry, u32 target) bool ppu_form_branch_to_code(u32 entry, u32 target, bool link)
{ {
entry &= -4; entry &= -4;
target &= -4; target &= -4;
@ -532,7 +534,7 @@ bool ppu_form_branch_to_code(u32 entry, u32 target)
auto& jumps = g_fxo->get<ppu_far_jumps_t>(); auto& jumps = g_fxo->get<ppu_far_jumps_t>();
std::lock_guard lock(jumps.mutex); std::lock_guard lock(jumps.mutex);
jumps.vals.insert_or_assign(entry, target); jumps.vals.insert_or_assign(entry, std::make_pair(target, link));
ppu_register_function_at(entry, 4, &ppu_far_jump); ppu_register_function_at(entry, 4, &ppu_far_jump);
return true; return true;
@ -691,7 +693,7 @@ std::array<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op)
g_fxo->need<ppu_far_jumps_t>(); g_fxo->need<ppu_far_jumps_t>();
if (u32 target = g_fxo->get<const ppu_far_jumps_t>().get_target(pc)) if (u32 target = g_fxo->get<const ppu_far_jumps_t>().get_target(pc).first)
{ {
res[0] = target; res[0] = target;
return res; return res;
@ -3253,9 +3255,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (!func.size) continue; if (!func.size) continue;
const auto name = fmt::format("__0x%x", func.addr - reloc); const auto name = fmt::format("__0x%x", func.addr - reloc);
const u64 addr = ensure(jit->get(name)); const auto addr = ensure(reinterpret_cast<ppu_function_t>(jit->get(name)));
jit_mod.funcs.emplace_back(reinterpret_cast<ppu_function_t>(addr)); jit_mod.funcs.emplace_back(addr);
ppu_register_function_at(func.addr, 4, jit_mod.funcs.back());
if (ppu_ref(func.addr) != reinterpret_cast<u64>(ppu_far_jump))
ppu_register_function_at(func.addr, 4, addr);
if (g_cfg.core.ppu_debug) if (g_cfg.core.ppu_debug)
ppu_log.notice("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc); ppu_log.notice("Installing function %s at 0x%x: %p (reloc = 0x%x)", name, func.addr, ppu_ref(func.addr), reloc);
@ -3272,8 +3276,10 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
{ {
if (!func.size) continue; if (!func.size) continue;
const u64 addr = ensure(reinterpret_cast<uptr>(jit_mod.funcs[index++])); const u64 addr = reinterpret_cast<uptr>(ensure(jit_mod.funcs[index++]));
ppu_ref(func.addr) = (addr & 0x7fff'ffff'ffffu) | (ppu_ref(func.addr) & ~0x7fff'ffff'ffffu);
if (ppu_ref(func.addr) != reinterpret_cast<u64>(ppu_far_jump))
ppu_register_function_at(func.addr, 4, addr);
if (g_cfg.core.ppu_debug) if (g_cfg.core.ppu_debug)
ppu_log.notice("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc); ppu_log.notice("Reinstalling function at 0x%x: %p (reloc=0x%x)", func.addr, ppu_ref(func.addr), reloc);

View File

@ -234,10 +234,11 @@ Function* PPUTranslator::Translate(const ppu_function& info)
m_rel = nullptr; m_rel = nullptr;
} }
if (u32 target = ppu_get_far_jump(m_addr + base)) if (ppu_get_far_jump(m_addr + base))
{ {
// Branch into an HLEd instruction using the jump table
FlushRegisters(); FlushRegisters();
CallFunction(0, m_ir->getInt64(target)); CallFunction(0, m_reloc ? m_ir->CreateAdd(m_ir->getInt64(m_addr), m_seg0) : m_ir->getInt64(m_addr));
continue; continue;
} }