diff --git a/Common/MachineContext.h b/Common/MachineContext.h index 0cac3d97ce..282a63c237 100644 --- a/Common/MachineContext.h +++ b/Common/MachineContext.h @@ -168,6 +168,17 @@ typedef sigcontext SContext; #define CTX_PC arm_pc #define CTX_REG(x) regs[x] +#elif PPSSPP_ARCH(RISCV64) + +#include +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 diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp index 49e349d44a..c7df046697 100644 --- a/Core/MemFault.cpp +++ b/Core/MemFault.cpp @@ -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