riscv: Implement basic crash handler.

Tested by letting it recover non-guest crashes.
This commit is contained in:
Unknown W. Brackets 2022-12-24 19:08:31 +00:00
parent f6c26ecac0
commit 4fa071e78a
2 changed files with 79 additions and 2 deletions

View File

@ -168,6 +168,17 @@ typedef sigcontext SContext;
#define CTX_PC arm_pc
#define CTX_REG(x) regs[x]
#elif PPSSPP_ARCH(RISCV64)
#include <ucontext.h>
typedef mcontext_t SContext;
#define MACHINE_CONTEXT_SUPPORTED
#define CTX_REG(x) __gregs[x]
#define CTX_PC CTX_REG(0)
#define CTX_SP CTX_REG(2)
#else
// No context definition for architecture

View File

@ -172,6 +172,68 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
ArmLSInstructionInfo info{};
success = ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info);
#elif PPSSPP_ARCH(RISCV64)
// TODO: Put in a disassembler.
struct RiscVLSInstructionInfo {
int instructionSize;
bool isIntegerLoadStore;
bool isFPLoadStore;
int size;
bool isMemoryWrite;
};
uint32_t word;
memcpy(&word, codePtr, 4);
RiscVLSInstructionInfo info{};
// Compressed instructions have low bits 00, 01, or 10.
info.instructionSize = (word & 3) == 3 ? 4 : 2;
instructionSize = info.instructionSize;
success = true;
switch (word & 0x7F) {
case 3:
info.isIntegerLoadStore = true;
info.size = 1 << ((word >> 12) & 3);
break;
case 7:
info.isFPLoadStore = true;
info.size = 1 << ((word >> 12) & 3);
break;
case 35:
info.isIntegerLoadStore = true;
info.isMemoryWrite = true;
info.size = 1 << ((word >> 12) & 3);
break;
case 39:
info.isFPLoadStore = true;
info.isMemoryWrite = true;
info.size = 1 << ((word >> 12) & 3);
break;
default:
// Compressed instruction.
switch (word & 0x6003) {
case 0x4000:
case 0x4002:
case 0x6000:
case 0x6002:
info.isIntegerLoadStore = true;
info.size = (word & 0x2000) != 0 ? 8 : 4;
info.isMemoryWrite = (word & 0x8000) != 0;
break;
case 0x2000:
case 0x2002:
info.isFPLoadStore = true;
info.size = 8;
info.isMemoryWrite = (word & 0x8000) != 0;
break;
default:
// Not a read or a write.
success = false;
break;
}
break;
}
#endif
std::string disassembly;
@ -204,6 +266,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
g_lastMemoryExceptionType = type;
bool handled = true;
if (success && (g_Config.bIgnoreBadMemAccess || g_ignoredAddresses.find(codePtr) != g_ignoredAddresses.end())) {
if (!info.isMemoryWrite) {
// It was a read. Fill the destination register with 0.
@ -224,12 +287,15 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
g_lastCrashAddress = codePtr;
// Redirect execution to a crash handler that will switch to CoreState::CORE_RUNTIME_ERROR immediately.
context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler();
if (MIPSComp::jit)
context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler();
else
handled = false;
ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str());
}
inCrashHandler = false;
return true;
return handled;
}
#else