mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 00:13:08 +00:00
Patch CPUID
This commit is contained in:
parent
28ec489dbe
commit
7d6a01cc29
@ -798,4 +798,50 @@ void PrePatchInstructions(u64 segment_addr, u64 segment_size) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We patch CPUID to handle it specially and simulate an AMD environment.
|
||||||
|
// Because CPUID is at minimum 2 bytes, a trampoline jump is not possible.
|
||||||
|
// Instead, we replace the instruction with an illegal instruction and handle it in the illegal instruction handler.
|
||||||
|
void PatchCPUID(u64 segment_addr, u64 segment_size) {
|
||||||
|
u8* code = reinterpret_cast<u8*>(segment_addr);
|
||||||
|
u8* end = code + segment_size;
|
||||||
|
bool previous_instruction_ok = false;
|
||||||
|
|
||||||
|
while (code < end) {
|
||||||
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||||
|
const auto status = ZydisDecoderDecodeFull(&instr_decoder, code, end - code, &instruction, operands);
|
||||||
|
|
||||||
|
if (!ZYAN_SUCCESS(status)) {
|
||||||
|
code++;
|
||||||
|
previous_instruction_ok = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction.mnemonic == ZYDIS_MNEMONIC_CPUID) {
|
||||||
|
if (!previous_instruction_ok) {
|
||||||
|
// It should be highly unlikely that the CPUID instruction is not preceded by a valid instruction.
|
||||||
|
// Instead of patching it we're going to skip it and generate a warning, because we could be in some
|
||||||
|
// data section that must not be changed.
|
||||||
|
LOG_ERROR(Core, "CPUID instruction is not preceded by a valid instruction at: {} while patching", fmt::ptr(code));
|
||||||
|
code++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_CRITICAL(Core, "FOUND CPUID INSTRUCTION AT: {}", fmt::ptr(code));
|
||||||
|
|
||||||
|
// Replace any potential prefixes and the 0F byte with single byte NOPs
|
||||||
|
u8 instruction_length = instruction.length;
|
||||||
|
for (u8 i = 0; i < instruction_length - 1; i++) {
|
||||||
|
code[i] = 0x90;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the CPUID instruction with an illegal instruction
|
||||||
|
code[instruction_length - 1] = 0x37; // 0x37 is AAA, illegal in x86-64
|
||||||
|
}
|
||||||
|
|
||||||
|
code += instruction.length;
|
||||||
|
previous_instruction_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -18,4 +18,7 @@ void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_are
|
|||||||
/// Applies CPU patches that need to be done before beginning executions.
|
/// Applies CPU patches that need to be done before beginning executions.
|
||||||
void PrePatchInstructions(u64 segment_addr, u64 segment_size);
|
void PrePatchInstructions(u64 segment_addr, u64 segment_size);
|
||||||
|
|
||||||
|
// Patches CPUID instructions with an illegal instruction to handle them specially in the signal handler
|
||||||
|
void PatchCPUID(u64 segment_addr, u64 segment_size);
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -137,6 +137,7 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
|
|||||||
#ifdef ARCH_X86_64
|
#ifdef ARCH_X86_64
|
||||||
if (elf_pheader[i].p_flags & PF_EXEC) {
|
if (elf_pheader[i].p_flags & PF_EXEC) {
|
||||||
PrePatchInstructions(segment_addr, segment_file_size);
|
PrePatchInstructions(segment_addr, segment_file_size);
|
||||||
|
PatchCPUID(segment_addr, segment_file_size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <intrin.h>
|
||||||
#else
|
#else
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <cpuid.h>
|
||||||
#ifdef ARCH_X86_64
|
#ifdef ARCH_X86_64
|
||||||
#include <Zydis/Decoder.h>
|
#include <Zydis/Decoder.h>
|
||||||
#include <Zydis/Formatter.h>
|
#include <Zydis/Formatter.h>
|
||||||
@ -31,9 +33,16 @@ static LONG WINAPI SignalHandler(EXCEPTION_POINTERS* pExp) noexcept {
|
|||||||
code_address, reinterpret_cast<void*>(pExp->ExceptionRecord->ExceptionInformation[1]),
|
code_address, reinterpret_cast<void*>(pExp->ExceptionRecord->ExceptionInformation[1]),
|
||||||
pExp->ExceptionRecord->ExceptionInformation[0] == 1);
|
pExp->ExceptionRecord->ExceptionInformation[0] == 1);
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
case EXCEPTION_ILLEGAL_INSTRUCTION: {
|
||||||
handled = signals->DispatchIllegalInstruction(code_address);
|
u8 opcode = *reinterpret_cast<u8*>(code_address);
|
||||||
|
if (opcode == 0x37) { // 0x37 is AAA instruction, we use that to patch CPUID
|
||||||
|
handled = EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
pExp->ContextRecord->Rip += 1; // skip the illegal instruction
|
||||||
|
} else {
|
||||||
|
handled = signals->DispatchIllegalInstruction(code_address);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -87,7 +96,7 @@ static std::string DisassembleInstruction(void* code_address) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SignalHandler(int sig, siginfo_t* info, void* raw_context) {
|
static void SignalHandler(int sig, siginfo_t* info, void* raw_context) {
|
||||||
const auto* ctx = static_cast<ucontext_t*>(raw_context);
|
auto* ctx = static_cast<ucontext_t*>(raw_context);
|
||||||
const auto* signals = Signals::Instance();
|
const auto* signals = Signals::Instance();
|
||||||
|
|
||||||
auto* code_address = CODE_ADDRESS(ctx);
|
auto* code_address = CODE_ADDRESS(ctx);
|
||||||
@ -102,12 +111,25 @@ static void SignalHandler(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
fmt::ptr(info->si_addr));
|
fmt::ptr(info->si_addr));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIGILL:
|
case SIGILL: {
|
||||||
if (!signals->DispatchIllegalInstruction(code_address)) {
|
u8 opcode = *reinterpret_cast<u8*>(code_address);
|
||||||
UNREACHABLE_MSG("Unhandled illegal instruction at code address {}: {}",
|
if (opcode == 0x37) { // 0x37 is AAA instruction, we use that to patch CPUID
|
||||||
fmt::ptr(code_address), DisassembleInstruction(code_address));
|
u64 results[4];
|
||||||
|
u64 eax = ctx->uc_mcontext.gregs[REG_RAX];
|
||||||
|
u64 ecx = ctx->uc_mcontext.gregs[REG_RCX];
|
||||||
|
LOG_WARNING(Core, "CPUID: eax=%lx ecx=%lx\n", eax, ecx);
|
||||||
|
__cpuid_count(eax, ecx, results[0], results[1], results[2], results[3]);
|
||||||
|
LOG_WARNING(Core, "RESULTS: %lx %lx %lx %lx\n", results[0], results[1], results[2], results[3]);
|
||||||
|
ctx->uc_mcontext.gregs[REG_RIP] += 1; // skip the illegal instruction
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!signals->DispatchIllegalInstruction(code_address)) {
|
||||||
|
UNREACHABLE_MSG("Unhandled illegal instruction at code address {}: {}",
|
||||||
|
fmt::ptr(code_address), DisassembleInstruction(code_address));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user