1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-21 18:22:33 +01:00

aarch64: Support calloc patch blocks

This commit is contained in:
kd-11 2024-08-31 05:56:54 +03:00 committed by kd-11
parent 4d193ecb6a
commit c80342e8d4
5 changed files with 65 additions and 12 deletions

View File

@ -1,7 +1,9 @@
#include "bin_patch.h" #include "bin_patch.h"
#include "ppu_patch.h"
#include "File.h" #include "File.h"
#include "Config.h" #include "Config.h"
#include "version.h" #include "version.h"
#include "Emu/IdManager.h"
#include "Emu/Memory/vm.h" #include "Emu/Memory/vm.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/VFS.h" #include "Emu/VFS.h"
@ -896,10 +898,6 @@ void patch_engine::append_title_patches(std::string_view title_id)
load(m_map, fmt::format("%s%s_patch.yml", get_patches_path(), title_id)); load(m_map, fmt::format("%s%s_patch.yml", get_patches_path(), title_id));
} }
void ppu_register_range(u32 addr, u32 size);
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
u32 ppu_generate_id(std::string_view name);
void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr) void unmap_vm_area(std::shared_ptr<vm::block_t>& ptr)
{ {
if (ptr && ptr->flags & (1ull << 62)) if (ptr && ptr->flags & (1ull << 62))
@ -1216,6 +1214,10 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
continue; continue;
} }
// Record the insertion point as a faux block.
g_fxo->need<ppu_patch_block_registry_t>();
g_fxo->get<ppu_patch_block_registry_t>().block_addresses.insert(resval);
relocate_instructions_at = addr; relocate_instructions_at = addr;
break; break;
} }

20
Utilities/ppu_patch.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <util/types.hpp>
#include <unordered_set>
#include <vector>
#include <string>
// Patch utilities specific to PPU code
struct ppu_patch_block_registry_t
{
ppu_patch_block_registry_t() = default;
ppu_patch_block_registry_t(const ppu_patch_block_registry_t&) = delete;
ppu_patch_block_registry_t& operator=(const ppu_patch_block_registry_t&) = delete;
std::unordered_set<u32> block_addresses{};
};
void ppu_register_range(u32 addr, u32 size);
bool ppu_form_branch_to_code(u32 entry, u32 target, bool link = false, bool with_toc = false, std::string module_name = {});
u32 ppu_generate_id(std::string_view name);

View File

@ -1,6 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "AArch64JIT.h" #include "AArch64JIT.h"
#include "AArch64ASM.h" #include "AArch64ASM.h"
@ -415,9 +414,9 @@ namespace aarch64
ensure(llvm::isa<llvm::ReturnInst>(where)); ensure(llvm::isa<llvm::ReturnInst>(where));
irb->SetInsertPoint(llvm::dyn_cast<llvm::Instruction>(where)); irb->SetInsertPoint(llvm::dyn_cast<llvm::Instruction>(where));
if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return if (instruction_info.callee_is_GHC && // Calls to C++ ABI will always return
!instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not !instruction_info.is_indirect && // We don't know enough when calling indirectly to know if we'll return or not
instruction_info.callee_name.find("-pp-") == umax) // Skip branch patch-points as those are just indirect calls. TODO: Move this to instruction decode. !is_faux_function(instruction_info.callee_name)) // Ignore branch patch-points and imposter functions. Their behavior is unreliable.
{ {
// We're making a one-way call. This branch shouldn't even bother linking as it will never return here. // We're making a one-way call. This branch shouldn't even bother linking as it will never return here.
ASMBlock c; ASMBlock c;
@ -487,6 +486,24 @@ namespace aarch64
return false; return false;
} }
bool GHC_frame_preservation_pass::is_faux_function(const std::string& function_name)
{
// Is it a branch patch-point?
if (function_name.find("-pp-") != umax)
{
return true;
}
// Now we search the known imposters list
if (m_config.faux_function_list.empty())
{
return false;
}
const auto& x = m_config.faux_function_list;
return std::find(x.begin(), x.end(), function_name) != x.end();
}
void GHC_frame_preservation_pass::process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f) void GHC_frame_preservation_pass::process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f)
{ {
for (auto &bb : f) for (auto &bb : f)

View File

@ -41,12 +41,13 @@ namespace aarch64
struct config_t struct config_t
{ {
bool debug_info = false; // Record debug information bool debug_info = false; // Record debug information
bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch. bool use_stack_frames = true; // Allocate a stack frame for each function. The gateway can alternatively manage a global stack to use as scratch.
bool optimize = true; // Optimize instructions when possible. Set to false when debugging. bool optimize = true; // Optimize instructions when possible. Set to false when debugging.
u32 hypervisor_context_offset = 0; // Offset within the "thread" object where we can find the hypervisor context (registers configured at gateway). u32 hypervisor_context_offset = 0; // Offset within the "thread" object where we can find the hypervisor context (registers configured at gateway).
std::function<bool(const std::string&)> exclusion_callback; // [Optional] Callback run on each function before transform. Return "true" to exclude from frame processing. std::function<bool(const std::string&)> exclusion_callback; // [Optional] Callback run on each function before transform. Return "true" to exclude from frame processing.
std::vector<std::pair<std::string, gpr>> base_register_lookup; // [Optional] Function lookup table to determine the location of the "thread" context. std::vector<std::pair<std::string, gpr>> base_register_lookup; // [Optional] Function lookup table to determine the location of the "thread" context.
std::vector<std::string> faux_function_list; // [Optional] List of faux block names to treat as untrusted - typically fake functions representing codecaves.
}; };
protected: protected:
@ -64,6 +65,8 @@ namespace aarch64
bool is_inlined_call(const llvm::CallInst* ci); bool is_inlined_call(const llvm::CallInst* ci);
bool is_faux_function(const std::string& function_name);
gpr get_base_register_for_call(const std::string& callee_name, gpr default_reg = gpr::x19); gpr get_base_register_for_call(const std::string& callee_name, gpr default_reg = gpr::x19);
void process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f); void process_leaf_function(llvm::IRBuilder<>* irb, llvm::Function& f);

View File

@ -18,6 +18,8 @@
#ifdef ARCH_ARM64 #ifdef ARCH_ARM64
#include "Emu/CPU/Backends/AArch64/AArch64JIT.h" #include "Emu/CPU/Backends/AArch64/AArch64JIT.h"
#include "Emu/IdManager.h"
#include "Utilities/ppu_patch.h"
#endif #endif
using namespace llvm; using namespace llvm;
@ -48,13 +50,22 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_mo
{ "__", aarch64::x19 } // Probably link table entries { "__", aarch64::x19 } // Probably link table entries
}; };
// Build list of imposter functions built by the patch manager.
g_fxo->need<ppu_patch_block_registry_t>();
std::vector<std::string> faux_functions_list;
for (const auto& a : g_fxo->get<ppu_patch_block_registry_t>().block_addresses)
{
faux_functions_list.push_back(fmt::format("__0x%x", a));
}
aarch64::GHC_frame_preservation_pass::config_t config = aarch64::GHC_frame_preservation_pass::config_t config =
{ {
.debug_info = false, // Set to "true" to insert debug frames on x27 .debug_info = false, // Set to "true" to insert debug frames on x27
.use_stack_frames = false, // We don't need this since the PPU GW allocates global scratch on the stack .use_stack_frames = false, // We don't need this since the PPU GW allocates global scratch on the stack
.hypervisor_context_offset = ::offset32(&ppu_thread::hv_ctx), .hypervisor_context_offset = ::offset32(&ppu_thread::hv_ctx),
.exclusion_callback = {}, // Unused, we don't have special exclusion functions on PPU .exclusion_callback = {}, // Unused, we don't have special exclusion functions on PPU
.base_register_lookup = base_reg_lookup .base_register_lookup = base_reg_lookup,
.faux_function_list = std::move(faux_functions_list)
}; };
// Create transform pass // Create transform pass