From 22ac7ad119ae2680efb168263a09833d5ea0a1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 10 Aug 2026 21:11:49 +0200 Subject: [PATCH] MemFault: move RISC-V and LoongArch fault analysis out of HandleFault The RISC-V branch had its instruction-decode logic (including a locally defined info struct) written directly inline in HandleFault(), unlike the other three architectures which each delegate to a dedicated AnalyzeLoadStore function in their disassembler file. Move it into ext/riscv-disas.h/.cpp as RiscVAnalyzeLoadStore, matching the existing X86AnalyzeMOV/Arm64AnalyzeLoadStore/ArmAnalyzeLoadStore pattern. --- Core/MemFault.cpp | 61 +++------------------------------------------ ext/riscv-disas.cpp | 51 +++++++++++++++++++++++++++++++++++++ ext/riscv-disas.h | 11 ++++++++ 3 files changed, 66 insertions(+), 57 deletions(-) diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp index a56e0059a9..8a946a2275 100644 --- a/Core/MemFault.cpp +++ b/Core/MemFault.cpp @@ -32,6 +32,8 @@ #include "Core/Util/DisArm64.h" #elif PPSSPP_ARCH(ARM) #include "ext/disarm.h" +#elif PPSSPP_ARCH(RISCV64) +#include "ext/riscv-disas.h" #elif PPSSPP_ARCH(LOONGARCH64) #include "ext/loongarch-disasm.h" #endif @@ -184,67 +186,12 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { 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); - + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC RiscVLSInstructionInfo info{}; - // Compressed instructions have low bits 00, 01, or 10. - info.instructionSize = (word & 3) == 3 ? 4 : 2; + success = RiscVAnalyzeLoadStore((uint64_t)codePtr, word, &info); 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; - } #elif PPSSPP_ARCH(LOONGARCH64) uint32_t word; memcpy(&word, codePtr, 4); diff --git a/ext/riscv-disas.cpp b/ext/riscv-disas.cpp index a4868ae50d..0825b68644 100644 --- a/ext/riscv-disas.cpp +++ b/ext/riscv-disas.cpp @@ -2526,3 +2526,54 @@ void riscv_disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_ins decode_inst_lift_pseudo(&dec); decode_inst_format(buf, buflen, 32, &dec); } + +/* PPSSPP: analyze a load/store instruction, used by the JIT crash handler */ + +bool RiscVAnalyzeLoadStore(uint64_t addr, uint32_t word, RiscVLSInstructionInfo *info) +{ + *info = {}; + // Compressed instructions have low bits 00, 01, or 10. + info->instructionSize = (word & 3) == 3 ? 4 : 2; + + switch (word & 0x7F) { + case 3: + info->isIntegerLoadStore = true; + info->size = 1 << ((word >> 12) & 3); + return true; + case 7: + info->isFPLoadStore = true; + info->size = 1 << ((word >> 12) & 3); + return true; + case 35: + info->isIntegerLoadStore = true; + info->isMemoryWrite = true; + info->size = 1 << ((word >> 12) & 3); + return true; + case 39: + info->isFPLoadStore = true; + info->isMemoryWrite = true; + info->size = 1 << ((word >> 12) & 3); + return true; + 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; + return true; + case 0x2000: + case 0x2002: + info->isFPLoadStore = true; + info->size = 8; + info->isMemoryWrite = (word & 0x8000) != 0; + return true; + default: + // Not a read or a write. + return false; + } + } +} diff --git a/ext/riscv-disas.h b/ext/riscv-disas.h index b7fcdfa509..1d43fc72c4 100644 --- a/ext/riscv-disas.h +++ b/ext/riscv-disas.h @@ -594,4 +594,15 @@ size_t riscv_inst_length(rv_inst inst); void riscv_inst_fetch(const uint8_t *data, rv_inst *instp, size_t *length); void riscv_disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst); +// PPSSPP: information about a load/store instruction, used by the JIT crash handler. +struct RiscVLSInstructionInfo { + int instructionSize; + bool isIntegerLoadStore; + bool isFPLoadStore; + int size; // Size of the access, in bytes (1, 2, 4, or 8). + bool isMemoryWrite; +}; + +bool RiscVAnalyzeLoadStore(uint64_t addr, uint32_t word, RiscVLSInstructionInfo *info); + #endif