Patch system improved

SPU patch rewritten
PPU patch implemented
This commit is contained in:
Nekotekina 2017-07-17 16:20:29 +03:00
parent 2ef2f0f63b
commit e39ee10105
3 changed files with 78 additions and 32 deletions

View File

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/VirtualMemory.h" #include "Utilities/VirtualMemory.h"
#include "Utilities/bin_patch.h"
#include "Crypto/sha1.h" #include "Crypto/sha1.h"
#include "Crypto/unself.h" #include "Crypto/unself.h"
#include "Loader/ELF.h" #include "Loader/ELF.h"
@ -954,6 +955,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
u32 primary_stacksize = 0x100000; u32 primary_stacksize = 0x100000;
u32 malloc_pagesize = 0x100000; u32 malloc_pagesize = 0x100000;
// Executable hash
sha1_context sha;
sha1_starts(&sha);
u8 sha1_hash[20];
// Allocate memory at fixed positions // Allocate memory at fixed positions
for (const auto& prog : elf.progs) for (const auto& prog : elf.progs)
{ {
@ -965,6 +971,10 @@ void ppu_load_exec(const ppu_exec_object& elf)
const u32 type = _seg.type = prog.p_type; const u32 type = _seg.type = prog.p_type;
const u32 flag = _seg.flags = prog.p_flags; const u32 flag = _seg.flags = prog.p_flags;
// Hash big-endian values
sha1_update(&sha, (uchar*)&prog.p_type, sizeof(prog.p_type));
sha1_update(&sha, (uchar*)&prog.p_flags, sizeof(prog.p_flags));
if (type == 0x1 /* LOAD */ && prog.p_memsz) if (type == 0x1 /* LOAD */ && prog.p_memsz)
{ {
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz) if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
@ -973,8 +983,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
if (!vm::falloc(addr, size, vm::main)) if (!vm::falloc(addr, size, vm::main))
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size); fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
// Copy segment data // Copy segment data, hash it
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
sha1_update(&sha, (uchar*)&prog.p_vaddr, sizeof(prog.p_vaddr));
sha1_update(&sha, (uchar*)&prog.p_memsz, sizeof(prog.p_memsz));
sha1_update(&sha, prog.bin.data(), prog.bin.size());
// Initialize executable code if necessary // Initialize executable code if necessary
if (prog.p_flags & 0x1) if (prog.p_flags & 0x1)
@ -1004,6 +1017,28 @@ void ppu_load_exec(const ppu_exec_object& elf)
} }
} }
sha1_finish(&sha, sha1_hash);
// Format patch name
std::string hash("PPU-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];
}
// Apply the patch
fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
}
LOG_NOTICE(LOADER, "PPU executable hash: %s", hash);
// Initialize HLE modules // Initialize HLE modules
ppu_initialize_modules(link); ppu_initialize_modules(link);

View File

@ -34,24 +34,13 @@ void sys_spu_image::load(const fs::file& stream)
const u32 addr = this->segs.addr() + 4096; const u32 addr = this->segs.addr() + 4096;
sha1_context ctx;
u8 output[20];
sha1_starts(&ctx);
sha1_update(&ctx, reinterpret_cast<const u8*>(&obj.header), sizeof(obj.header));
for (const auto& shdr : obj.shdrs) for (const auto& shdr : obj.shdrs)
{ {
sha1_update(&ctx, reinterpret_cast<const u8*>(&shdr), sizeof(spu_exec_object::shdr_t));
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags); LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
} }
for (const auto& prog : obj.progs) for (const auto& prog : obj.progs)
{ {
sha1_update(&ctx, reinterpret_cast<const u8*>(&prog), sizeof(spu_exec_object::phdr_t));
sha1_update(&ctx, reinterpret_cast<const u8*>(prog.bin.data()), prog.bin.size());
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY) if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
@ -85,22 +74,6 @@ void sys_spu_image::load(const fs::file& stream)
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type); LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
} }
} }
sha1_finish(&ctx, output);
// Format patch name
std::string hash("spu-");
for (u8 x : output) fmt::append(hash, "%02x", x);
LOG_NOTICE(LOADER, "Loaded SPU image: %s", hash);
// Apply the patch
fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + addr);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + addr);
}
} }
void sys_spu_image::free() void sys_spu_image::free()
@ -113,15 +86,29 @@ void sys_spu_image::free()
void sys_spu_image::deploy(u32 loc) void sys_spu_image::deploy(u32 loc)
{ {
// Segment info dump
std::string dump;
// Executable hash
sha1_context sha;
sha1_starts(&sha);
u8 sha1_hash[20];
for (int i = 0; i < nsegs; i++) for (int i = 0; i < nsegs; i++)
{ {
auto& seg = segs[i]; auto& seg = segs[i];
LOG_NOTICE(SPU, "*** Deploy: t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", seg.type, seg.ls, seg.size, seg.addr); fmt::append(dump, "\n\t[%d] t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", i, seg.type, seg.ls, seg.size, seg.addr);
// Hash big-endian values
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY) if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
{ {
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size); std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
} }
else if (seg.type == SYS_SPU_SEGMENT_TYPE_FILL) else if (seg.type == SYS_SPU_SEGMENT_TYPE_FILL)
{ {
@ -131,8 +118,32 @@ void sys_spu_image::deploy(u32 loc)
} }
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr); std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
} }
} }
sha1_finish(&sha, 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];
}
// Apply the patch
fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + loc);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + loc);
}
LOG_NOTICE(LOADER, "Loaded SPU image: %s%s", hash, dump);
} }
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)

View File

@ -98,13 +98,13 @@ struct elf_phdr<en_t, u32>
template<template<typename T> class en_t, typename sz_t> template<template<typename T> class en_t, typename sz_t>
struct elf_prog final : elf_phdr<en_t, sz_t> struct elf_prog final : elf_phdr<en_t, sz_t>
{ {
std::vector<char> bin; std::vector<uchar> bin;
using base = elf_phdr<en_t, sz_t>; using base = elf_phdr<en_t, sz_t>;
elf_prog() = default; elf_prog() = default;
elf_prog(u32 type, u32 flags, sz_t vaddr, sz_t memsz, sz_t align, std::vector<char>&& bin) elf_prog(u32 type, u32 flags, sz_t vaddr, sz_t memsz, sz_t align, std::vector<uchar>&& bin)
: bin(std::move(bin)) : bin(std::move(bin))
{ {
base::p_type = type; base::p_type = type;