mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-10 17:01:24 +12:00
Embedded SPU elf patching
- PS3 games include both PPU and SPU code in their PPU executables, so to make patching games that make use of the same SPU libraries easier, we add a system to find and patch them. - Patches for this system still use SPU LS (Local Storage) addresses despite the fact that we aren't loading anything into SPU LS at this time. The patches are checked against each segment and patched in place.
This commit is contained in:
parent
7f07b79c04
commit
ad8988afd3
3 changed files with 151 additions and 0 deletions
|
@ -1148,6 +1148,80 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
// Initialize HLE modules
|
||||
ppu_initialize_modules(link);
|
||||
|
||||
// Embedded SPU elf patching
|
||||
for (u32 i = _main->segs[0].addr; i < (_main->segs[0].addr + _main->segs[0].size); i += 4)
|
||||
{
|
||||
uchar* elf_header = vm::_ptr<u8>(i);
|
||||
const spu_exec_object obj(fs::file(vm::base(vm::cast(i, HERE)), (_main->segs[0].addr + _main->segs[0].size) - i));
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
// This address does not have an SPU elf
|
||||
continue;
|
||||
}
|
||||
|
||||
// Segment info dump
|
||||
std::string dump;
|
||||
|
||||
applied = 0;
|
||||
|
||||
// Executable hash
|
||||
sha1_context sha2;
|
||||
sha1_starts(&sha2);
|
||||
u8 sha1_hash[20];
|
||||
|
||||
for (const auto& prog : obj.progs)
|
||||
{
|
||||
// Only hash the data, we are not loading it
|
||||
sha1_update(&sha2, reinterpret_cast<const uchar*>(&prog.p_vaddr), sizeof(prog.p_vaddr));
|
||||
sha1_update(&sha2, reinterpret_cast<const uchar*>(&prog.p_memsz), sizeof(prog.p_memsz));
|
||||
sha1_update(&sha2, reinterpret_cast<const uchar*>(&prog.p_filesz), sizeof(prog.p_filesz));
|
||||
|
||||
fmt::append(dump, "\n\tSegment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, p_offset=0x%llx", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_offset);
|
||||
|
||||
if (prog.p_type == 0x1 /* LOAD */ && prog.p_filesz > 0)
|
||||
{
|
||||
sha1_update(&sha2, (elf_header + prog.p_offset), prog.p_filesz);
|
||||
}
|
||||
|
||||
else if (prog.p_type == 0x4 /* NOTE */ && prog.p_filesz > 0)
|
||||
{
|
||||
sha1_update(&sha2, (elf_header + prog.p_offset), prog.p_filesz);
|
||||
|
||||
// We assume that the string SPUNAME exists 0x14 bytes into the NOTE segment
|
||||
const auto spu_name = reinterpret_cast<const char*>(elf_header + prog.p_offset + 0x14);
|
||||
fmt::append(dump, "\n\tSPUNAME: '%s'", spu_name);
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&sha2, sha1_hash);
|
||||
|
||||
// Format patch name
|
||||
std::string hash("SPU-0000000000000000000000000000000000000000");
|
||||
for (u32 i = 0; i < sizeof(sha1_hash); i++)
|
||||
{
|
||||
constexpr auto pal = "0123456789abcdef";
|
||||
hash[4 + i * 2] = pal[sha1_hash[i] >> 4];
|
||||
hash[5 + i * 2] = pal[sha1_hash[i] & 15];
|
||||
}
|
||||
|
||||
// Try to patch each segment, will only succeed if the address exists in SPU local storage
|
||||
for (const auto& prog : obj.progs)
|
||||
{
|
||||
// Apply the patch
|
||||
applied += g_fxo->get<patch_engine>()->apply_with_ls_check(hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += g_fxo->get<patch_engine>()->apply_with_ls_check(Emu.GetTitleID() + '-' + hash, (elf_header + prog.p_offset), prog.p_filesz, prog.p_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "SPU executable hash: %s (<- %u)%s", hash, applied, dump);
|
||||
|
||||
}
|
||||
|
||||
// Static HLE patching
|
||||
if (g_cfg.core.hook_functions)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue