PPU: HACK instruction removed

Breakpoints fixed
This commit is contained in:
Nekotekina 2017-03-22 23:23:47 +03:00
parent ddd6ebc58d
commit 3bfe17a14f
20 changed files with 155 additions and 379 deletions

View File

@ -13,7 +13,6 @@
logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
extern s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 count);
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr);
const u32 tiled_pitches[] = {
0x00000000, 0x00000200, 0x00000300, 0x00000400,
@ -379,13 +378,7 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
current_context.current = current_context.begin;
current_context.callback.set(gcm_info.context_addr + 0x40);
vm::write32(gcm_info.context_addr + 0x40, gcm_info.context_addr + 0x48);
vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe);
vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback)));
vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR());
ppu_register_function_at(gcm_info.context_addr + 0x48, 8, BIND_FUNC(cellGcmCallback));
current_context.callback.set(ppu_function_manager::addr + 8 * FIND_FUNC(cellGcmCallback));
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
context->set(gcm_info.context_addr);

View File

@ -689,7 +689,6 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
}
if (ptr + 8 <= fend &&
(ptr[0] == STD(r2, r1, 0x28) && (ptr[1] & 0xfc000000) == HACK(0) && ptr[2] == BLR() ||
(ptr[0] & 0xffff0000) == LI(r12, 0) &&
(ptr[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(ptr[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
@ -697,7 +696,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
ptr[4] == LWZ(r0, r12, 0) &&
ptr[5] == LWZ(r2, r12, 4) &&
ptr[6] == MTCTR(r0) &&
ptr[7] == BCTR()))
ptr[7] == BCTR())
{
// The most used simple import stub
func.size = 0x20;
@ -709,7 +708,6 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
auto p2 = ptr + 8;
while (p2 + 8 <= fend &&
(p2[0] == STD(r2, r1, 0x28) && (p2[1] & 0xfc000000) == HACK(0) && p2[2] == BLR() ||
(p2[0] & 0xffff0000) == LI(r12, 0) &&
(p2[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(p2[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
@ -717,7 +715,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
p2[4] == LWZ(r0, r12, 0) &&
p2[5] == LWZ(r2, r12, 4) &&
p2[6] == MTCTR(r0) &&
p2[7] == BCTR()))
p2[7] == BCTR())
{
auto& next = add_func(p2.addr(), 0, func.addr);
next.size = 0x20;

View File

@ -274,7 +274,6 @@ struct ppu_itype
ADDI,
ADDIS,
BC,
HACK,
SC,
B,
MCRF,
@ -691,7 +690,6 @@ struct ppu_iflag
ADDI = read_ra,
ADDIS = read_ra,
BC = 0,
HACK = 0,
SC = 0,
B = 0,
MCRF = 0,
@ -1093,7 +1091,6 @@ struct ppu_iname
NAME(ADDI)
NAME(ADDIS)
NAME(BC)
NAME(HACK)
NAME(SC)
NAME(B)
NAME(MCRF)

View File

@ -892,11 +892,6 @@ void PPUDisAsm::BC(ppu_opcode_t op)
Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi / 4, bi % 4, bd, aa, lk));
}
void PPUDisAsm::HACK(ppu_opcode_t op)
{
Write(fmt::format("hack %d", op.opcode & 0x3ffffff));
}
void PPUDisAsm::SC(ppu_opcode_t op)
{
if (op.opcode != ppu_instructions::SC(0))

View File

@ -397,7 +397,6 @@ public:
void ADDI(ppu_opcode_t op);
void ADDIS(ppu_opcode_t op);
void BC(ppu_opcode_t op);
void HACK(ppu_opcode_t op);
void SC(ppu_opcode_t op);
void B(ppu_opcode_t op);
void MCRF(ppu_opcode_t op);

View File

@ -2381,8 +2381,17 @@ std::vector<ppu_function_t>& ppu_function_manager::access()
{
static std::vector<ppu_function_t> list
{
nullptr,
[](ppu_thread& ppu) { ppu.state += cpu_flag::ret; },
[](ppu_thread& ppu) -> bool
{
LOG_ERROR(PPU, "Unregistered function called (LR=0x%x)", ppu.lr);
ppu.gpr[3] = 0;
return true;
},
[](ppu_thread& ppu) -> bool
{
ppu.state += cpu_flag::ret;
return true;
},
};
return list;
@ -2396,3 +2405,5 @@ u32 ppu_function_manager::add_function(ppu_function_t function)
return ::size32(list) - 1;
}
DECLARE(ppu_function_manager::addr);

View File

@ -2,15 +2,16 @@
#include "PPUThread.h"
using ppu_function_t = void(*)(ppu_thread&);
using ppu_function_t = bool(*)(ppu_thread&);
// BIND_FUNC macro "converts" any appropriate HLE function to ppu_function_t, binding it to PPU thread context.
#define BIND_FUNC(func) (static_cast<ppu_function_t>([](ppu_thread& ppu) {\
#define BIND_FUNC(func) (static_cast<ppu_function_t>([](ppu_thread& ppu) -> bool {\
const auto old_f = ppu.last_function;\
ppu.last_function = #func;\
ppu_func_detail::do_call(ppu, func);\
ppu.test_state();\
ppu.last_function = old_f;\
return true;\
}))
struct ppu_va_args_t
@ -274,6 +275,9 @@ public:
{
return access();
}
// Allocation address
static u32 addr;
};
template<typename T, T Func>

View File

@ -1936,12 +1936,6 @@ bool ppu_interpreter::BC(ppu_thread& ppu, ppu_opcode_t op)
}
}
bool ppu_interpreter::HACK(ppu_thread& ppu, ppu_opcode_t op)
{
ppu_execute_function(ppu, op.opcode & 0x3ffffff);
return true;
}
bool ppu_interpreter::SC(ppu_thread& ppu, ppu_opcode_t op)
{
if (op.opcode != ppu_instructions::SC(0))

View File

@ -160,7 +160,6 @@ struct ppu_interpreter
static bool ADDI(ppu_thread&, ppu_opcode_t);
static bool ADDIS(ppu_thread&, ppu_opcode_t);
static bool BC(ppu_thread&, ppu_opcode_t);
static bool HACK(ppu_thread&, ppu_opcode_t);
static bool SC(ppu_thread&, ppu_opcode_t);
static bool B(ppu_thread&, ppu_opcode_t);
static bool MCRF(ppu_thread&, ppu_opcode_t);

View File

@ -13,7 +13,8 @@
#include "Emu/Cell/lv2/sys_prx.h"
#include <unordered_set>
#include <map>
#include <set>
#include <algorithm>
namespace vm { using namespace ps3; }
@ -118,6 +119,7 @@ cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries");
extern std::string ppu_get_function_name(const std::string& module, u32 fnid);
extern std::string ppu_get_variable_name(const std::string& module, u32 vnid);
extern void ppu_register_range(u32 addr, u32 size);
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr);
extern void ppu_initialize(const ppu_module& info);
extern void ppu_initialize();
@ -125,53 +127,6 @@ extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
extern u32 g_ps3_sdk_version;
// Function lookup table. Not supposed to grow after emulation start.
std::vector<ppu_function_t> g_ppu_function_cache;
// Function name cache in format %s.%s (module name, function name)
std::vector<std::string> g_ppu_function_names;
// Function NID cache for autopause. Autopause tool should probably be rewritten.
std::vector<u32> g_ppu_fnid_cache;
extern std::string ppu_get_module_function_name(u32 index)
{
if (index < g_ppu_function_names.size())
{
return g_ppu_function_names[index];
}
return fmt::format(".%u", index);
}
extern void ppu_execute_function(ppu_thread& ppu, u32 index)
{
if (index < g_ppu_function_cache.size())
{
// If autopause occures, check_status() will hold the thread until unpaused
if (debug::autopause::pause_function(g_ppu_fnid_cache[index])) ppu.test_state();
if (const auto func = g_ppu_function_cache[index])
{
func(ppu);
LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.gpr[3]);
return;
}
}
fmt::throw_exception("Function not registered (index %u)" HERE, index);
}
extern ppu_function_t ppu_get_function(u32 index)
{
if (index < g_ppu_function_cache.size())
{
return g_ppu_function_cache[index];
}
return nullptr;
}
extern u32 ppu_generate_id(const char* name)
{
// Symbol name suffix
@ -224,6 +179,26 @@ const ppu_static_module* ppu_module_manager::get_module(const std::string& name)
return found != map.end() ? found->second : nullptr;
}
// Global linkage information
struct ppu_linkage_info
{
struct module
{
struct info
{
u32 export_addr = 0;
std::set<u32> imports;
};
// FNID -> (export; [imports...])
std::map<u32, info> functions;
std::map<u32, info> variables;
};
// Module map
std::unordered_map<std::string, module> modules;
};
// Initialize static modules.
static void ppu_initialize_modules()
{
@ -323,13 +298,6 @@ static void ppu_initialize_modules()
&ppu_module_manager::sys_lv2dbg,
};
// Reinitialize function cache
g_ppu_function_cache = ppu_function_manager::get();
g_ppu_function_names.clear();
g_ppu_function_names.resize(g_ppu_function_cache.size());
g_ppu_fnid_cache.clear();
g_ppu_fnid_cache.resize(g_ppu_function_cache.size());
// "Use" all the modules for correct linkage
for (auto& module : registered)
{
@ -338,8 +306,6 @@ static void ppu_initialize_modules()
for (auto& function : module->functions)
{
LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name);
g_ppu_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name);
g_ppu_fnid_cache.at(function.second.index) = function.first;
}
for (auto& variable : module->variables)
@ -348,152 +314,31 @@ static void ppu_initialize_modules()
variable.second.var->set(0);
}
}
// Initialize double-purpose fake OPD array for HLE functions
const auto& hle_funcs = ppu_function_manager::get();
// Allocate memory for the array (must be called after fixed allocations)
ppu_function_manager::addr = vm::alloc(::size32(hle_funcs) * 8, vm::main);
// Initialize as PPU executable code
ppu_register_range(ppu_function_manager::addr, ::size32(hle_funcs) * 8);
// Fill the array (visible data: self address and function index)
for (u32 addr = ppu_function_manager::addr, index = 0; index < hle_funcs.size(); addr += 8, index++)
{
// Function address = current address, RTOC = BLR instruction for the interpreter
vm::ps3::write32(addr + 0, addr);
vm::ps3::write32(addr + 4, ppu_instructions::BLR());
// Register the HLE function directly
ppu_register_function_at(addr + 0, 4, hle_funcs[index]);
}
// Set memory protection to read-only
vm::page_protect(ppu_function_manager::addr, ::align(::size32(hle_funcs) * 8, 0x1000), 0, 0, vm::page_writable);
}
// Detect import stub at specified address and inject HACK instruction with index immediate.
static bool ppu_patch_import_stub(u32 addr, u32 index)
{
const auto data = vm::_ptr<u32>(addr);
using namespace ppu_instructions;
// Check various patterns:
if (vm::check_addr(addr, 32) &&
(data[0] & 0xffff0000) == LI(r12, 0) &&
(data[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(data[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[3] == STD(r2, r1, 0x28) &&
data[4] == LWZ(r0, r12, 0) &&
data[5] == LWZ(r2, r12, 4) &&
data[6] == MTCTR(r0) &&
data[7] == BCTR())
{
data[0] = STD(r2, r1, 0x28); // Save RTOC
data[1] = HACK(index);
data[2] = BLR();
std::fill(data + 3, data + 8, NOP());
return true;
}
if (vm::check_addr(addr, 12) &&
(data[0] & 0xffff0000) == LI(r0, 0) &&
(data[1] & 0xffff0000) == ORIS(r0, r0, 0) &&
(data[2] & 0xfc000003) == B(0, 0, 0))
{
const auto sub = vm::cptr<u32>::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2));
if (vm::check_addr(sub.addr(), 60) &&
sub[0x0] == STDU(r1, r1, -0x80) &&
sub[0x1] == STD(r2, r1, 0x70) &&
sub[0x2] == MR(r2, r0) &&
sub[0x3] == MFLR(r0) &&
sub[0x4] == STD(r0, r1, 0x90) &&
sub[0x5] == LWZ(r2, r2, 0) &&
sub[0x6] == LWZ(r0, r2, 0) &&
sub[0x7] == LWZ(r2, r2, 4) &&
sub[0x8] == MTCTR(r0) &&
sub[0x9] == BCTRL() &&
sub[0xa] == LD(r2, r1, 0x70) &&
sub[0xb] == ADDI(r1, r1, 0x80) &&
sub[0xc] == LD(r0, r1, 0x10) &&
sub[0xd] == MTLR(r0) &&
sub[0xe] == BLR())
{
data[0] = HACK(index);
data[1] = BLR();
data[2] = NOP();
return true;
}
}
if (vm::check_addr(addr, 64) &&
data[0x0] == MFLR(r0) &&
data[0x1] == STD(r0, r1, 0x10) &&
data[0x2] == STDU(r1, r1, -0x80) &&
data[0x3] == STD(r2, r1, 0x70) &&
(data[0x4] & 0xffff0000) == LI(r2, 0) &&
(data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) &&
data[0x6] == LWZ(r2, r2, 0) &&
data[0x7] == LWZ(r0, r2, 0) &&
data[0x8] == LWZ(r2, r2, 4) &&
data[0x9] == MTCTR(r0) &&
data[0xa] == BCTRL() &&
data[0xb] == LD(r2, r1, 0x70) &&
data[0xc] == ADDI(r1, r1, 0x80) &&
data[0xd] == LD(r0, r1, 0x10) &&
data[0xe] == MTLR(r0) &&
data[0xf] == BLR())
{
data[0] = HACK(index);
data[1] = BLR();
std::fill(data + 2, data + 16, NOP());
return true;
}
if (vm::check_addr(addr, 60) &&
data[0x0] == MFLR(r0) &&
data[0x1] == STD(r0, r1, 0x10) &&
data[0x2] == STDU(r1, r1, -0x80) &&
data[0x3] == STD(r2, r1, 0x70) &&
(data[0x4] & 0xffff0000) == LIS(r12, 0) &&
(data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[0x6] == LWZ(r0, r12, 0) &&
data[0x7] == LWZ(r2, r12, 4) &&
data[0x8] == MTCTR(r0) &&
data[0x9] == BCTRL() &&
data[0xa] == LD(r2, r1, 0x70) &&
data[0xb] == ADDI(r1, r1, 0x80) &&
data[0xc] == LD(r0, r1, 0x10) &&
data[0xd] == MTLR(r0) &&
data[0xe] == BLR())
{
data[0] = HACK(index);
data[1] = BLR();
std::fill(data + 2, data + 15, NOP());
return true;
}
if (vm::check_addr(addr, 56) &&
(data[0x0] & 0xffff0000) == LI(r12, 0) &&
(data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[0x3] == STD(r2, r1, 0x28) &&
data[0x4] == MFLR(r0) &&
data[0x5] == STD(r0, r1, 0x20) &&
data[0x6] == LWZ(r0, r12, 0) &&
data[0x7] == LWZ(r2, r12, 4) &&
data[0x8] == MTCTR(r0) &&
data[0x9] == BCTRL() &&
data[0xa] == LD(r0, r1, 0x20) &&
data[0xb] == MTLR(r0) &&
data[0xc] == LD(r2, r1, 0x28) &&
data[0xd] == BLR())
{
data[0] = HACK(index);
data[1] = BLR();
std::fill(data + 2, data + 14, NOP());
return true;
}
return false;
}
// Global linkage information
struct ppu_linkage_info
{
struct module
{
using info_t = std::unordered_map<u32, std::pair<u32, std::unordered_set<u32>>>;
info_t functions;
info_t variables;
};
// Module -> (NID -> (export; [imports...]))
std::unordered_map<std::string, module> modules;
};
// Link variable
static void ppu_patch_variable_refs(u32 vref, u32 vaddr)
{
@ -605,7 +450,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
// Function linkage info
auto& flink = link->modules[module_name].functions[fnid];
if (flink.first)
if (flink.export_addr)
{
LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
}
@ -616,18 +461,32 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
if (_sf && (_sf->flags & MFF_FORCED_HLE))
{
// Inject HACK instruction (TODO: guess function size and analyse B instruction, or reimplement BLR flag for HACK instruction)
const auto code = vm::ptr<u32>::make(vm::read32(faddr));
code[0] = ppu_instructions::HACK(_sf->index);
code[1] = ppu_instructions::BLR();
// Inject a branch to the HLE implementation
const u32 _entry = vm::read32(faddr);
const u32 target = ppu_function_manager::addr + 8 * _sf->index;
if ((target <= _entry && _entry - target <= 0x2000000) || (target > _entry && target - _entry < 0x2000000))
{
// Use relative branch
vm::write32(_entry, ppu_instructions::B(target - _entry));
}
else if (target < 0x2000000)
{
// Use absolute branch if possible
vm::write32(_entry, ppu_instructions::B(target, true));
}
else
{
LOG_FATAL(LOADER, "Failed to patch function at 0x%x (0x%x)", _entry, target);
}
}
else
{
// Set exported function
flink.first = faddr;
flink.export_addr = faddr;
// Fix imports
for (const auto addr : flink.second)
for (const u32 addr : flink.imports)
{
vm::write32(addr, faddr);
//LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
@ -649,17 +508,17 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
// Variable linkage info
auto& vlink = link->modules[module_name].variables[vnid];
if (vlink.first)
if (vlink.export_addr)
{
LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
}
else
{
// Set exported variable
vlink.first = vaddr;
vlink.export_addr = vaddr;
// Fix imports
for (const auto vref : vlink.second)
for (const auto vref : vlink.imports)
{
ppu_patch_variable_refs(vref, vaddr);
//LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
@ -705,10 +564,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
auto& flink = link->modules[module_name].functions[fnid];
// Add new import
flink.second.emplace(faddr);
flink.imports.emplace(faddr);
// Link if available
if (flink.first) vm::write32(faddr, flink.first);
if (flink.export_addr)
{
vm::write32(faddr, flink.export_addr);
}
//LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr);
}
@ -726,10 +588,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
auto& vlink = link->modules[module_name].variables[vnid];
// Add new import
vlink.second.emplace(vref);
vlink.imports.emplace(vref);
// Link if available
if (vlink.first) ppu_patch_variable_refs(vref, vlink.first);
if (vlink.export_addr)
{
ppu_patch_variable_refs(vref, vlink.export_addr);
}
//LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first);
}
@ -940,8 +805,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
void ppu_load_exec(const ppu_exec_object& elf)
{
ppu_initialize_modules();
if (g_cfg_hook_ppu_funcs)
{
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
@ -996,6 +859,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}
// Load section list, used by the analyser
for (const auto& s : elf.shdrs)
{
LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags);
@ -1009,6 +873,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}
// Initialize HLE modules
ppu_initialize_modules();
// Load other programs
for (auto& prog : elf.progs)
{
@ -1296,55 +1163,31 @@ void ppu_load_exec(const ppu_exec_object& elf)
for (auto& entry : module.second.functions)
{
const u32 fnid = entry.first;
const u32 faddr = entry.second.first;
const u32 faddr = entry.second.export_addr;
if (faddr == 0)
{
const std::string fname = ppu_get_function_name(module.first, fnid);
// Link HLE implementation if available
if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr)
{
// Static function
for (auto& import : entry.second.second)
{
const u32 stub = vm::read32(import);
LOG_NOTICE(LOADER, "Linking HLE function '%s' in module '%s' (index %u)", fname, module.first, _sf->index);
if (!ppu_patch_import_stub(stub, _sf->index))
{
LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", _sf->name, module.first, stub);
}
else
{
LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", _sf->name, module.first, stub);
}
for (const u32 import : entry.second.imports)
{
LOG_TRACE(LOADER, "** Linked at *0x%x (0x%x)", import, vm::read32(import));
vm::write32(import, ppu_function_manager::addr + 8 * _sf->index);
}
}
else
{
// TODO
const u32 index = ::size32(g_ppu_function_cache);
const std::string& fname = ppu_get_function_name(module.first, fnid);
g_ppu_function_cache.emplace_back();
g_ppu_function_names.emplace_back(fmt::format("%s.%s", module.first, fname));
g_ppu_fnid_cache.emplace_back(fnid);
LOG_ERROR(LOADER, "Unknown function '%s' in module '%s'", fname, module.first);
LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", fname, module.first, index);
for (auto& import : entry.second.second)
for (const u32 import : entry.second.imports)
{
if (_sm)
{
const u32 stub = vm::read32(import);
if (!ppu_patch_import_stub(stub, index))
{
LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", fname, module.first, stub);
}
else
{
LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", fname, module.first, stub);
}
}
LOG_WARNING(LOADER, "** Not linked at *0x%x", import);
LOG_WARNING(LOADER, "** Not linked at *0x%x (0x%x)", import, vm::read32(import));
vm::write32(import, ppu_function_manager::addr);
}
}
}
@ -1353,16 +1196,18 @@ void ppu_load_exec(const ppu_exec_object& elf)
for (auto& entry : module.second.variables)
{
const u32 vnid = entry.first;
const u32 vaddr = entry.second.first;
const u32 vaddr = entry.second.export_addr;
if (vaddr == 0)
{
// Static variable
const std::string vname = ppu_get_variable_name(module.first, vnid);
// Link HLE variable if available
if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr)
{
LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", ppu_get_variable_name(module.first, vnid), module.first, _sv->var->addr());
LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", vname, module.first, _sv->var->addr());
for (auto& ref : entry.second.second)
for (const u32 ref : entry.second.imports)
{
ppu_patch_variable_refs(ref, _sv->var->addr());
LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref);
@ -1370,9 +1215,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
else
{
LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", ppu_get_variable_name(module.first, vnid), module.first);
LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", vname, module.first);
for (auto& ref : entry.second.second)
for (const u32 ref : entry.second.imports)
{
LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref);
}

View File

@ -121,7 +121,6 @@ public:
// Main opcodes (field 0..5)
fill_table(0x00, 6, -1,
{
{ 0x01, &D::HACK },
{ 0x02, &D::TDI },
{ 0x03, &D::TWI },
{ 0x07, &D::MULLI },
@ -609,7 +608,6 @@ namespace ppu_instructions
namespace implicts
{
inline u32 HACK(u32 index) { return 0x01 << 26 | index; }
inline u32 NOP() { return ORI(r0, r0, 0); }
inline u32 MR(u32 rt, u32 ra) { return OR(rt, ra, ra, false); }
inline u32 LI(u32 rt, u32 imm) { return ADDI(rt, r0, imm); }

View File

@ -102,7 +102,6 @@ const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
extern void ppu_initialize();
extern void ppu_initialize(const ppu_module& info);
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code);
extern void ppu_execute_function(ppu_thread& ppu, u32 index);
const auto s_ppu_compiled = static_cast<u32*>(utils::memory_reserve(0x100000000));
@ -157,24 +156,34 @@ extern void ppu_register_range(u32 addr, u32 size)
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr)
{
// Initialize specific function
if (ptr)
{
s_ppu_compiled[addr / 4] = ::narrow<u32>(reinterpret_cast<std::uintptr_t>(ptr));
return;
}
if (!size)
{
LOG_ERROR(PPU, "ppu_register_function_at(0x%x): empty range", addr);
return;
}
ppu_register_range(addr, size);
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
{
s_ppu_compiled[addr / 4] = ::narrow<u32>(reinterpret_cast<std::uintptr_t>(ptr));
return;
}
// Initialize interpreter cache
const u32 fallback = ::narrow<u32>(reinterpret_cast<std::uintptr_t>(ppu_fallback));
while (size)
{
s_ppu_compiled[addr / 4] = ppu_cache(addr);
if (s_ppu_compiled[addr / 4] == fallback)
{
s_ppu_compiled[addr / 4] = ppu_cache(addr);
}
addr += 4;
size -= 4;
}
@ -354,7 +363,7 @@ void ppu_thread::cpu_task()
}
case ppu_cmd::hle_call:
{
cmd_pop(), ppu_execute_function(*this, arg);
cmd_pop(), ppu_function_manager::get().at(arg)(*this);
break;
}
case ppu_cmd::initialize:
@ -379,7 +388,8 @@ void ppu_thread::exec_task()
{
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
{
return reinterpret_cast<ppu_function_t>((std::uintptr_t)s_ppu_compiled[cia / 4])(*this);
reinterpret_cast<ppu_function_t>(static_cast<std::uintptr_t>(s_ppu_compiled[cia / 4]))(*this);
return;
}
const auto base = vm::_ptr<const u8>(0);
@ -558,7 +568,7 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
cia = addr;
gpr[2] = rtoc;
lr = Emu.GetCPUThreadStop();
lr = ppu_function_manager::addr + 8; // HLE stop address
last_function = nullptr;
g_tls_log_prefix = []
@ -662,8 +672,6 @@ const ppu_decoder<ppu_itype> s_ppu_itype;
extern u64 get_timebased_time();
extern ppu_function_t ppu_get_syscall(u64 code);
extern std::string ppu_get_syscall_name(u64 code);
extern ppu_function_t ppu_get_function(u32 index);
extern std::string ppu_get_module_function_name(u32 index);
extern __m128 sse_exp2_ps(__m128 A);
extern __m128 sse_log2_ps(__m128 A);
@ -782,25 +790,6 @@ extern void ppu_initialize()
return;
}
if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm || _funcs->empty())
{
if (!Emu.GetCPUThreadStop())
{
auto ppu_thr_stop_data = vm::ptr<u32>::make(vm::alloc(2 * 4, vm::main));
Emu.SetCPUThreadStop(ppu_thr_stop_data.addr());
ppu_thr_stop_data[0] = ppu_instructions::HACK(1);
ppu_thr_stop_data[1] = ppu_instructions::BLR();
ppu_register_function_at(ppu_thr_stop_data.addr(), 8, nullptr);
}
for (const auto& func : *_funcs)
{
ppu_register_function_at(func.addr, func.size, nullptr);
}
return;
}
std::size_t fpos = 0;
while (fpos < _funcs->size())
@ -891,7 +880,6 @@ extern void ppu_initialize(const ppu_module& info)
{ "__end", (u64)&ppu_unreachable },
{ "__check", (u64)&ppu_check },
{ "__trace", (u64)&ppu_trace },
{ "__hlecall", (u64)&ppu_execute_function },
{ "__syscall", (u64)&ppu_execute_syscall },
{ "__get_tb", (u64)&get_timebased_time },
{ "__lwarx", (u64)&ppu_lwarx },
@ -918,18 +906,6 @@ extern void ppu_initialize(const ppu_module& info)
}
}
for (u64 index = 1; ; index++)
{
if (auto func = ppu_get_function(index))
{
link_table.emplace(ppu_get_module_function_name(index), (u64)func);
}
else
{
break;
}
}
const auto jit = fxm::make<jit_compiler>(std::move(link_table), g_cfg_llvm_cpu.get());
LOG_SUCCESS(PPU, "LLVM: JIT initialized (%s)", jit->cpu());
@ -1058,7 +1034,6 @@ extern void ppu_initialize(const ppu_module& info)
pm.run(*func);
const auto _syscall = module->getFunction("__syscall");
const auto _hlecall = module->getFunction("__hlecall");
for (auto i = inst_begin(*func), end = inst_end(*func); i != end;)
{
@ -1084,20 +1059,6 @@ extern void ppu_initialize(const ppu_module& info)
}
}
if (cif == _hlecall && op1 && isa<ConstantInt>(op1))
{
const u32 index = static_cast<u32>(cast<ConstantInt>(op1)->getZExtValue());
if (const auto ptr = ppu_get_function(index))
{
const auto n = ppu_get_module_function_name(index);
const auto f = cast<Function>(module->getOrInsertFunction(n, _func));
// Call the function directly
ReplaceInstWithInst(ci, CallInst::Create(f, {ci->getArgOperand(0)}));
}
}
continue;
}

View File

@ -1775,12 +1775,6 @@ void PPUTranslator::BC(ppu_opcode_t op)
CallFunction(target, !op.lk);
}
void PPUTranslator::HACK(ppu_opcode_t op)
{
Call(GetType<void>(), "__hlecall", m_thread, m_ir->getInt32(op.opcode & 0x3ffffff));
UndefineVolatileRegisters();
}
void PPUTranslator::SC(ppu_opcode_t op)
{
if (op.opcode != ppu_instructions::SC(0) && op.opcode != ppu_instructions::SC(1))

View File

@ -599,7 +599,6 @@ public:
void ADDI(ppu_opcode_t op);
void ADDIS(ppu_opcode_t op);
void BC(ppu_opcode_t op);
void HACK(ppu_opcode_t op);
void SC(ppu_opcode_t op);
void B(ppu_opcode_t op);
void MCRF(ppu_opcode_t op);

View File

@ -54,3 +54,5 @@ u32 arm_function_manager::add_function(arm_function_t function)
return ::size32(list) - 1;
}
DECLARE(arm_function_manager::addr);

View File

@ -468,6 +468,9 @@ public:
{
return access();
}
// Allocation address
static u32 addr;
};
template<typename T, T Func>

View File

@ -630,7 +630,7 @@ void arm_load_exec(const arm_exec_object& elf)
const auto stop_code = vm::ptr<u32>::make(vm::alloc(3 * 4, vm::main));
stop_code[0] = 0xf870; // HACK instruction (Thumb)
stop_code[1] = 1; // Predefined function index (HLE return)
Emu.SetCPUThreadStop(stop_code.addr());
arm_function_manager::addr = stop_code.addr();
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024;

View File

@ -6,6 +6,7 @@
#include "ARMv7Thread.h"
#include "ARMv7Opcodes.h"
#include "ARMv7Interpreter.h"
#include "ARMv7Function.h"
#include "Utilities/GSL.h"
@ -122,7 +123,7 @@ void ARMv7Thread::fast_call(u32 addr)
const auto old_func = last_function;
PC = addr;
LR = Emu.GetCPUThreadStop();
LR = arm_function_manager::addr; // TODO
last_function = nullptr;
auto at_ret = gsl::finally([&]()

View File

@ -62,12 +62,6 @@ namespace rpcs3
event<void>& on_resume() { static event<void> on_resume; return on_resume; }
}
Emulator::Emulator()
: m_status(Stopped)
, m_cpu_thr_stop(0)
{
}
void Emulator::Init()
{
if (!g_tty)
@ -106,8 +100,6 @@ void Emulator::Init()
fs::create_dir(dev_hdd1 + "game/");
fs::create_path(dev_hdd1);
fs::create_path(dev_usb);
SetCPUThreadStop(0);
}
void Emulator::SetPath(const std::string& path, const std::string& elf_path)

View File

@ -39,15 +39,13 @@ enum Status : u32
class Emulator final
{
atomic_t<u32> m_status;
atomic_t<u32> m_status{Stopped};
EmuCallbacks m_cb;
atomic_t<u64> m_pause_start_time; // set when paused
atomic_t<u64> m_pause_amend_time; // increased when resumed
u32 m_cpu_thr_stop;
std::string m_path;
std::string m_elf_path;
std::string m_cache_path;
@ -55,7 +53,7 @@ class Emulator final
std::string m_title;
public:
Emulator();
Emulator() = default;
void SetCallbacks(EmuCallbacks&& cb)
{
@ -109,13 +107,6 @@ public:
return m_pause_amend_time;
}
void SetCPUThreadStop(u32 addr)
{
m_cpu_thr_stop = addr;
}
u32 GetCPUThreadStop() const { return m_cpu_thr_stop; }
bool BootGame(const std::string& path, bool direct = false);
static std::string GetGameDir();