mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
ARM/ARM64 instruction analysis, hook up to handler
This commit is contained in:
parent
aa802ecc0f
commit
c988d42b04
18 changed files with 202 additions and 51 deletions
|
@ -19,7 +19,7 @@ public:
|
||||||
CodeBlockCommon() {}
|
CodeBlockCommon() {}
|
||||||
virtual ~CodeBlockCommon() {}
|
virtual ~CodeBlockCommon() {}
|
||||||
|
|
||||||
bool IsInSpace(const u8 *ptr) {
|
bool IsInSpace(const u8 *ptr) const {
|
||||||
return (ptr >= region) && (ptr < (region + region_size));
|
return (ptr >= region) && (ptr < (region + region_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Common/ExceptionHandlerSetup.h"
|
#include "Common/ExceptionHandlerSetup.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -84,6 +83,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INFO_LOG(SYSTEM, "Installing exception handler");
|
||||||
g_badAccessHandler = badAccessHandler;
|
g_badAccessHandler = badAccessHandler;
|
||||||
g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, Handler);
|
g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, Handler);
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||||
void UninstallExceptionHandler() {
|
void UninstallExceptionHandler() {
|
||||||
RemoveVectoredExceptionHandler(g_vectoredExceptionHandle);
|
RemoveVectoredExceptionHandler(g_vectoredExceptionHandle);
|
||||||
g_badAccessHandler = nullptr;
|
g_badAccessHandler = nullptr;
|
||||||
|
INFO_LOG(SYSTEM, "Removed exception handler");
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE)
|
#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE)
|
||||||
|
@ -186,7 +187,14 @@ static void ExceptionThread(mach_port_t port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||||
g_badAccessHandler = badAccessHandler;
|
if (!g_badAccessHandler) {
|
||||||
|
g_badAccessHandler = badAccessHandler;
|
||||||
|
} else {
|
||||||
|
// The rest of the setup we don't need to do again.
|
||||||
|
g_badAccessHandler = badAccessHandler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
INFO_LOG(SYSTEM, "Installing exception handler");
|
||||||
mach_port_t port;
|
mach_port_t port;
|
||||||
CheckKR("mach_port_allocate",
|
CheckKR("mach_port_allocate",
|
||||||
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port));
|
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port));
|
||||||
|
@ -275,6 +283,10 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||||
|
if (g_badAccessHandler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NOTICE_LOG(SYSTEM, "Installed exception handler");
|
||||||
g_badAccessHandler = badAccessHandler;
|
g_badAccessHandler = badAccessHandler;
|
||||||
|
|
||||||
stack_t signal_stack;
|
stack_t signal_stack;
|
||||||
|
@ -308,10 +320,14 @@ void UninstallExceptionHandler() {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
sigaction(SIGBUS, &old_sa_bus, nullptr);
|
sigaction(SIGBUS, &old_sa_bus, nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
NOTICE_LOG(SYSTEM, "Uninstalled exception handler");
|
||||||
|
g_badAccessHandler = nullptr;
|
||||||
}
|
}
|
||||||
#else // _M_GENERIC or unsupported platform
|
#else // _M_GENERIC or unsupported platform
|
||||||
|
|
||||||
void InstallExceptionHandler(BadAccessHandler badAccessHandler) { }
|
void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
|
||||||
|
ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install");
|
||||||
|
}
|
||||||
void UninstallExceptionHandler() { }
|
void UninstallExceptionHandler() { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "x64Analyzer.h"
|
#include "x64Analyzer.h"
|
||||||
|
|
||||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info)
|
bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info)
|
||||||
{
|
{
|
||||||
int accessType = 0;
|
int accessType = 0;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
struct InstructionInfo
|
struct LSInstructionInfo
|
||||||
{
|
{
|
||||||
int operandSize; //8, 16, 32, 64
|
int operandSize; //8, 16, 32, 64
|
||||||
int instructionSize;
|
int instructionSize;
|
||||||
|
@ -60,4 +60,4 @@ enum AccessType {
|
||||||
OP_ACCESS_WRITE = 1
|
OP_ACCESS_WRITE = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info);
|
bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info);
|
||||||
|
|
|
@ -237,6 +237,7 @@ void ArmJit::GenerateFixedCode() {
|
||||||
CMP(R0, 0);
|
CMP(R0, 0);
|
||||||
B_CC(CC_EQ, outerLoop);
|
B_CC(CC_EQ, outerLoop);
|
||||||
|
|
||||||
|
const uint8_t *quitLoop = GetCodePtr();
|
||||||
SetJumpTarget(badCoreState);
|
SetJumpTarget(badCoreState);
|
||||||
|
|
||||||
SaveDowncount();
|
SaveDowncount();
|
||||||
|
@ -251,6 +252,12 @@ void ArmJit::GenerateFixedCode() {
|
||||||
|
|
||||||
POP(9, R4, R5, R6, R7, R8, R9, R10, R11, R_PC); // Returns
|
POP(9, R4, R5, R6, R7, R8, R9, R10, R11, R_PC); // Returns
|
||||||
|
|
||||||
|
crashHandler = GetCodePtr();
|
||||||
|
MOVP2R(R0, &coreState);
|
||||||
|
MOVI2R(R1, CORE_ERROR);
|
||||||
|
STR(R1, R0, 0);
|
||||||
|
B(quitLoop);
|
||||||
|
|
||||||
// Uncomment if you want to see the output...
|
// Uncomment if you want to see the output...
|
||||||
if (disasm) {
|
if (disasm) {
|
||||||
INFO_LOG(JIT, "THE DISASM ========================");
|
INFO_LOG(JIT, "THE DISASM ========================");
|
||||||
|
|
|
@ -51,6 +51,8 @@ public:
|
||||||
|
|
||||||
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
||||||
|
|
||||||
|
const u8 *GetCrashHandler() const override { return crashHandler; }
|
||||||
|
bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); }
|
||||||
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
||||||
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
||||||
|
|
||||||
|
@ -313,6 +315,8 @@ public:
|
||||||
|
|
||||||
const u8 *restoreRoundingMode;
|
const u8 *restoreRoundingMode;
|
||||||
const u8 *applyRoundingMode;
|
const u8 *applyRoundingMode;
|
||||||
|
|
||||||
|
const u8 *crashHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace MIPSComp
|
} // namespace MIPSComp
|
||||||
|
|
|
@ -277,6 +277,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) {
|
||||||
CMP(SCRATCH1, 0);
|
CMP(SCRATCH1, 0);
|
||||||
B(CC_EQ, outerLoop);
|
B(CC_EQ, outerLoop);
|
||||||
|
|
||||||
|
const uint8_t *quitLoop = GetCodePtr();
|
||||||
SetJumpTarget(badCoreState);
|
SetJumpTarget(badCoreState);
|
||||||
|
|
||||||
SaveStaticRegisters();
|
SaveStaticRegisters();
|
||||||
|
@ -286,6 +287,12 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) {
|
||||||
|
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
crashHandler = GetCodePtr();
|
||||||
|
MOVP2R(SCRATCH1_64, &coreState);
|
||||||
|
MOVI2R(SCRATCH2, CORE_ERROR);
|
||||||
|
STR(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0);
|
||||||
|
B(quitLoop);
|
||||||
|
|
||||||
// Generate some integer conversion funcs.
|
// Generate some integer conversion funcs.
|
||||||
// MIPS order!
|
// MIPS order!
|
||||||
static const RoundingMode roundModes[8] = { ROUND_N, ROUND_Z, ROUND_P, ROUND_M, ROUND_N, ROUND_Z, ROUND_P, ROUND_M };
|
static const RoundingMode roundModes[8] = { ROUND_N, ROUND_Z, ROUND_P, ROUND_M, ROUND_N, ROUND_Z, ROUND_P, ROUND_M };
|
||||||
|
|
|
@ -52,6 +52,8 @@ public:
|
||||||
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
||||||
const u8 *DoJit(u32 em_address, JitBlock *b);
|
const u8 *DoJit(u32 em_address, JitBlock *b);
|
||||||
|
|
||||||
|
const u8 *GetCrashHandler() const override { return crashHandler; }
|
||||||
|
bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); }
|
||||||
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
||||||
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
MIPSOpcode GetOriginalOp(MIPSOpcode op) override;
|
||||||
|
|
||||||
|
@ -281,6 +283,8 @@ public:
|
||||||
const u8 *applyRoundingMode;
|
const u8 *applyRoundingMode;
|
||||||
const u8 *updateRoundingMode;
|
const u8 *updateRoundingMode;
|
||||||
|
|
||||||
|
const u8 *crashHandler;
|
||||||
|
|
||||||
int jitStartOffset;
|
int jitStartOffset;
|
||||||
|
|
||||||
// Indexed by FPCR FZ:RN bits for convenience. Uses SCRATCH2.
|
// Indexed by FPCR FZ:RN bits for convenience. Uses SCRATCH2.
|
||||||
|
|
|
@ -160,7 +160,12 @@ public:
|
||||||
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
||||||
void UpdateFCR31() override;
|
void UpdateFCR31() override;
|
||||||
|
|
||||||
|
bool CodeInRange(const u8 *ptr) const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const u8 *GetDispatcher() const override { return nullptr; }
|
const u8 *GetDispatcher() const override { return nullptr; }
|
||||||
|
const u8 *GetCrashHandler() const override { return nullptr; }
|
||||||
|
|
||||||
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
|
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
|
||||||
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
|
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
|
||||||
|
|
|
@ -121,8 +121,10 @@ namespace MIPSComp {
|
||||||
public:
|
public:
|
||||||
virtual ~JitInterface() {}
|
virtual ~JitInterface() {}
|
||||||
|
|
||||||
|
virtual bool CodeInRange(const u8 *ptr) const = 0;
|
||||||
virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0;
|
virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0;
|
||||||
virtual const u8 *GetDispatcher() const = 0;
|
virtual const u8 *GetDispatcher() const = 0;
|
||||||
|
virtual const u8 *GetCrashHandler() const = 0;
|
||||||
virtual JitBlockCache *GetBlockCache() = 0;
|
virtual JitBlockCache *GetBlockCache() = 0;
|
||||||
virtual JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() = 0;
|
virtual JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() = 0;
|
||||||
virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0;
|
virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0;
|
||||||
|
|
|
@ -206,11 +206,21 @@ void Jit::GenerateFixedCode(JitOptions &jo) {
|
||||||
}
|
}
|
||||||
J_CC(CC_Z, outerLoop, true);
|
J_CC(CC_Z, outerLoop, true);
|
||||||
|
|
||||||
|
const uint8_t *quitLoop = GetCodePtr();
|
||||||
SetJumpTarget(badCoreState);
|
SetJumpTarget(badCoreState);
|
||||||
RestoreRoundingMode(true);
|
RestoreRoundingMode(true);
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
|
crashHandler = GetCodePtr();
|
||||||
|
if (RipAccessible((const void *)&coreState)) {
|
||||||
|
MOV(32, M(&coreState), Imm32(CORE_RUNTIME_ERROR));
|
||||||
|
} else {
|
||||||
|
MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState));
|
||||||
|
MOV(32, MatR(RAX), Imm32(CORE_RUNTIME_ERROR));
|
||||||
|
}
|
||||||
|
JMP(quitLoop, true);
|
||||||
|
|
||||||
// Let's spare the pre-generated code from unprotect-reprotect.
|
// Let's spare the pre-generated code from unprotect-reprotect.
|
||||||
endOfPregeneratedCode = AlignCodePage();
|
endOfPregeneratedCode = AlignCodePage();
|
||||||
EndWrite();
|
EndWrite();
|
||||||
|
|
|
@ -442,6 +442,8 @@ bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) {
|
||||||
name = "enterDispatcher";
|
name = "enterDispatcher";
|
||||||
else if (ptr == restoreRoundingMode)
|
else if (ptr == restoreRoundingMode)
|
||||||
name = "restoreRoundingMode";
|
name = "restoreRoundingMode";
|
||||||
|
else if (ptr == crashHandler)
|
||||||
|
name = "crashHandler";
|
||||||
else {
|
else {
|
||||||
u32 jitAddr = blocks.GetAddressFromBlockPtr(ptr);
|
u32 jitAddr = blocks.GetAddressFromBlockPtr(ptr);
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ public:
|
||||||
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
void Compile(u32 em_address) override; // Compiles a block at current MIPS PC
|
||||||
const u8 *DoJit(u32 em_address, JitBlock *b);
|
const u8 *DoJit(u32 em_address, JitBlock *b);
|
||||||
|
|
||||||
|
const u8 *GetCrashHandler() const override { return crashHandler; }
|
||||||
|
bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); }
|
||||||
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
|
||||||
|
|
||||||
void Comp_RunBlock(MIPSOpcode op) override;
|
void Comp_RunBlock(MIPSOpcode op) override;
|
||||||
|
@ -325,6 +327,8 @@ private:
|
||||||
|
|
||||||
const u8 *endOfPregeneratedCode;
|
const u8 *endOfPregeneratedCode;
|
||||||
|
|
||||||
|
const u8 *crashHandler;
|
||||||
|
|
||||||
friend class JitSafeMem;
|
friend class JitSafeMem;
|
||||||
friend class JitSafeMemFuncs;
|
friend class JitSafeMemFuncs;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,8 +28,20 @@
|
||||||
#include "Common/MemoryUtil.h"
|
#include "Common/MemoryUtil.h"
|
||||||
#include "Common/MemArena.h"
|
#include "Common/MemArena.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86)
|
||||||
#include "Common/MachineContext.h"
|
#include "Common/MachineContext.h"
|
||||||
#include "Common/x64Analyzer.h"
|
#include "Common/x64Analyzer.h"
|
||||||
|
#elif defined(PPSSPP_ARCH_ARM64)
|
||||||
|
#include "Core/Util/DisArm64.h"
|
||||||
|
typedef sigcontext SContext;
|
||||||
|
#define CTX_PC pc
|
||||||
|
#elif defined(PPSSPP_ARCH_ARM)
|
||||||
|
#include "ext/disarm.h"
|
||||||
|
typedef sigcontext SContext;
|
||||||
|
#define CTX_PC arm_pc
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Core/MemMap.h"
|
#include "Core/MemMap.h"
|
||||||
#include "Core/HDRemaster.h"
|
#include "Core/HDRemaster.h"
|
||||||
|
@ -43,6 +55,8 @@
|
||||||
#include "Core/ConfigValues.h"
|
#include "Core/ConfigValues.h"
|
||||||
#include "Core/HLE/ReplaceTables.h"
|
#include "Core/HLE/ReplaceTables.h"
|
||||||
#include "Core/MIPS/JitCommon/JitBlockCache.h"
|
#include "Core/MIPS/JitCommon/JitBlockCache.h"
|
||||||
|
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||||
|
#include "UI/OnScreenDisplay.h"
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
|
@ -87,6 +101,8 @@ u32 g_PSPModel;
|
||||||
|
|
||||||
std::recursive_mutex g_shutdownLock;
|
std::recursive_mutex g_shutdownLock;
|
||||||
|
|
||||||
|
static int64_t g_numReportedBadAccesses = 0;
|
||||||
|
|
||||||
// We don't declare the IO region in here since its handled by other means.
|
// We don't declare the IO region in here since its handled by other means.
|
||||||
static MemoryView views[] =
|
static MemoryView views[] =
|
||||||
{
|
{
|
||||||
|
@ -292,6 +308,8 @@ void Init() {
|
||||||
|
|
||||||
INFO_LOG(MEMMAP, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)",
|
INFO_LOG(MEMMAP, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)",
|
||||||
base, m_pPhysicalRAM, m_pUncachedRAM);
|
base, m_pPhysicalRAM, m_pUncachedRAM);
|
||||||
|
|
||||||
|
g_numReportedBadAccesses = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reinit() {
|
void Reinit() {
|
||||||
|
@ -464,7 +482,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
||||||
const uint8_t *codePtr = (uint8_t *)(context->CTX_PC);
|
const uint8_t *codePtr = (uint8_t *)(context->CTX_PC);
|
||||||
|
|
||||||
// TODO: Check that codePtr is within the current JIT space.
|
// TODO: Check that codePtr is within the current JIT space.
|
||||||
bool inJitSpace = true; // MIPSComp::jit->IsInSpace(codePtr);
|
bool inJitSpace = MIPSComp::jit->CodeInRange(codePtr);
|
||||||
if (!inJitSpace) {
|
if (!inJitSpace) {
|
||||||
// This is a crash in non-jitted code. Not something we want to handle here, ignore.
|
// This is a crash in non-jitted code. Not something we want to handle here, ignore.
|
||||||
return false;
|
return false;
|
||||||
|
@ -486,32 +504,49 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
||||||
// OK, a guest executable did a bad access. Take care of it.
|
// OK, a guest executable did a bad access. Take care of it.
|
||||||
|
|
||||||
uint32_t guestAddress = hostAddress - baseAddress;
|
uint32_t guestAddress = hostAddress - baseAddress;
|
||||||
ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, hostAddress);
|
|
||||||
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
|
// TODO: Share the struct between the various analyzers, that will allow us to share most of
|
||||||
|
// the implementations here.
|
||||||
|
|
||||||
#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86)
|
#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86)
|
||||||
|
// X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail.
|
||||||
|
|
||||||
InstructionInfo info;
|
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
|
||||||
DisassembleMov(codePtr, info);
|
LSInstructionInfo info;
|
||||||
|
X86AnalyzeMOV(codePtr, info);
|
||||||
|
#elif defined(PPSSPP_ARCH_ARM64)
|
||||||
|
uint32_t word;
|
||||||
|
memcpy(&word, codePtr, 4);
|
||||||
|
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
|
||||||
|
Arm64LSInstructionInfo info;
|
||||||
|
Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info);
|
||||||
|
#elif defined(PPSSPP_ARCH_ARM)
|
||||||
|
uint32_t word;
|
||||||
|
memcpy(&word, codePtr, 4);
|
||||||
|
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
|
||||||
|
ArmLSInstructionInfo info;
|
||||||
|
ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (g_Config.bIgnoreBadMemAccess) {
|
if (g_Config.bIgnoreBadMemAccess) {
|
||||||
if (!info.isMemoryWrite) {
|
if (!info.isMemoryWrite) {
|
||||||
// Must have been a read. Fill the register with 0.
|
// It was a read. Fill the destination register with 0.
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
// Move on to the next instruction.
|
// Move on to the next instruction.
|
||||||
context->CTX_PC += info.instructionSize;
|
context->CTX_PC += info.instructionSize;
|
||||||
|
// Fall through to logging.
|
||||||
} else {
|
} else {
|
||||||
// Jump to a crash handler.
|
// Jump to a crash handler that will exit the game.
|
||||||
// TODO
|
context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler();
|
||||||
context->CTX_PC += info.instructionSize;
|
ERROR_LOG(SYSTEM, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
g_numReportedBadAccesses++;
|
||||||
// ARM, ARM64 : All instructions are always 4 bytes in size. As an initial implementation,
|
if (g_numReportedBadAccesses < 100) {
|
||||||
// let's just skip the offending instruction.
|
ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress);
|
||||||
context->CTX_PC += 4;
|
}
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,41 @@ static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *ins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *info) {
|
||||||
|
*info = {};
|
||||||
|
info->instructionSize = 4;
|
||||||
|
int id = (w >> 25) & 0xF;
|
||||||
|
switch (id) {
|
||||||
|
case 4: case 6: case 0xC: case 0xE:
|
||||||
|
info->isLoadOrStore = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR_LOG(CPU, "Tried to disassemble %08x at %p as a load/store instruction", w, (void *)addr);
|
||||||
|
return; // not the expected instruction
|
||||||
|
}
|
||||||
|
|
||||||
|
info->size = w >> 30;
|
||||||
|
info->Rt = (w & 0x1F);
|
||||||
|
info->Rn = ((w >> 5) & 0x1F);
|
||||||
|
info->Rm = ((w >> 16) & 0x1F);
|
||||||
|
int opc = (w >> 22) & 0x3;
|
||||||
|
if (opc == 0 || opc == 2) {
|
||||||
|
info->isMemoryWrite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((w >> 27) & 7) == 7) {
|
||||||
|
int V = (w >> 26) & 1;
|
||||||
|
if (V == 0) {
|
||||||
|
info->isIntegerLoadStore = true;
|
||||||
|
} else {
|
||||||
|
info->isFPLoadStore = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info->isPairLoadStore = true;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) {
|
static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) {
|
||||||
int size = w >> 30;
|
int size = w >> 30;
|
||||||
int imm9 = SignExtend9((w >> 12) & 0x1FF);
|
int imm9 = SignExtend9((w >> 12) & 0x1FF);
|
||||||
|
|
|
@ -24,3 +24,24 @@ typedef bool (*SymbolCallback)(char *buffer, int bufsize, uint8_t *address);
|
||||||
|
|
||||||
void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback = nullptr);
|
void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback = nullptr);
|
||||||
|
|
||||||
|
// Information about a load/store instruction.
|
||||||
|
struct Arm64LSInstructionInfo {
|
||||||
|
int instructionSize;
|
||||||
|
|
||||||
|
bool isLoadOrStore;
|
||||||
|
|
||||||
|
bool isIntegerLoadStore;
|
||||||
|
bool isFPLoadStore;
|
||||||
|
bool isPairLoadStore;
|
||||||
|
|
||||||
|
int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit
|
||||||
|
bool isMemoryWrite;
|
||||||
|
|
||||||
|
int Rt;
|
||||||
|
int Rn;
|
||||||
|
int Rm;
|
||||||
|
|
||||||
|
// TODO: more.
|
||||||
|
};
|
||||||
|
|
||||||
|
void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t op, Arm64LSInstructionInfo *info);
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "Common/ArmEmitter.h"
|
#include "Common/ArmEmitter.h"
|
||||||
|
#include "ext/disarm.h"
|
||||||
|
|
||||||
static const char *CCFlagsStr[] = {
|
static const char *CCFlagsStr[] = {
|
||||||
"EQ", // Equal
|
"EQ", // Equal
|
||||||
|
@ -759,30 +760,12 @@ static bool DisasmNeon(uint32_t op, char *text) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info) {
|
||||||
|
*info = {};
|
||||||
|
info->instructionSize = 4;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned int word;
|
typedef unsigned int word;
|
||||||
|
|
30
ext/disarm.h
30
ext/disarm.h
|
@ -17,18 +17,34 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
// This stuff only disassembles very old ARM but should be sufficient
|
// This stuff used to only disassemble very old ARM but has now
|
||||||
// for the basics except for MOVW/MOVT.
|
// been extended to support most (but not all) modern instructions, including NEON.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Disarm itself has the license you can see in the cpp file.
|
// Disarm itself has the license you can see in the cpp file.
|
||||||
// I'm not entirely sure it's 100% gpl compatible but it's nearly
|
// I'm not entirely sure it's 100% gpl compatible but it's nearly
|
||||||
// public domain so meh.
|
// public domain so meh.
|
||||||
|
|
||||||
// The only changes I've done is C++ compat and replaced the main
|
|
||||||
// program with this function.
|
|
||||||
|
|
||||||
const char *ArmRegName(int r);
|
const char *ArmRegName(int r);
|
||||||
void ArmDis(unsigned int addr, unsigned int w, char *output, int bufsize, bool includeWord);
|
void ArmDis(unsigned int addr, unsigned int w, char *output, int bufsize, bool includeWord);
|
||||||
|
|
||||||
|
// Information about a load/store instruction.
|
||||||
|
struct ArmLSInstructionInfo {
|
||||||
|
int instructionSize;
|
||||||
|
|
||||||
|
bool isIntegerLoadStore;
|
||||||
|
bool isFPLoadStore;
|
||||||
|
bool isMultiLoadStore;
|
||||||
|
|
||||||
|
int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit
|
||||||
|
bool isMemoryWrite;
|
||||||
|
|
||||||
|
int Rt;
|
||||||
|
int Rn;
|
||||||
|
int Rm;
|
||||||
|
|
||||||
|
// TODO: more.
|
||||||
|
};
|
||||||
|
|
||||||
|
void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info);
|
||||||
|
|
Loading…
Add table
Reference in a new issue