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::code_alloc: return "calloc";
case patch_type::jump: return "jump";
case patch_type::jump_link: return "jumpl";
case patch_type::load: return "load";
case patch_type::byte: return "byte";
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);
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)
{
@ -737,12 +738,13 @@ static usz apply_modification(std::basic_string<u32>& applied, const patch_engin
break;
}
case patch_type::jump:
case patch_type::jump_link:
{
const u32 out_branch = vm::try_get_addr(dst + (offset & -4)).first;
const u32 dest = static_cast<u32>(p.value.long_value);
// 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;
}

View File

@ -29,6 +29,7 @@ enum class patch_type
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)
jump, // Install special 32-bit jump instruction (PPU only atm)
jump_link, // jump + set link (PPU only atm)
byte,
le16,
le32,

View File

@ -528,7 +528,7 @@ struct ppu_prx_module_info
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)
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
{
std::unordered_map<u32, u32> vals;
std::unordered_map<u32, std::pair<u32, bool>> vals;
mutable shared_mutex mutex;
u32 get_target(u32 pc) const
std::pair<u32, bool> get_target(u32 pc) const
{
reader_lock lock(mutex);
@ -500,23 +500,25 @@ struct ppu_far_jumps_t
return it->second;
}
return 0;
return {};
}
};
u32 ppu_get_far_jump(u32 pc)
{
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)
{
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;
}
bool ppu_form_branch_to_code(u32 entry, u32 target)
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link)
{
entry &= -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>();
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);
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>();
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;
return res;
@ -3253,9 +3255,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
if (!func.size) continue;
const auto name = fmt::format("__0x%x", func.addr - reloc);
const u64 addr = ensure(jit->get(name));
jit_mod.funcs.emplace_back(reinterpret_cast<ppu_function_t>(addr));
ppu_register_function_at(func.addr, 4, jit_mod.funcs.back());
const auto addr = ensure(reinterpret_cast<ppu_function_t>(jit->get(name)));
jit_mod.funcs.emplace_back(addr);
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)
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;
const u64 addr = ensure(reinterpret_cast<uptr>(jit_mod.funcs[index++]));
ppu_ref(func.addr) = (addr & 0x7fff'ffff'ffffu) | (ppu_ref(func.addr) & ~0x7fff'ffff'ffffu);
const u64 addr = reinterpret_cast<uptr>(ensure(jit_mod.funcs[index++]));
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)
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;
}
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();
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;
}