rpcsx/rpcs3/Emu/CPU/Backends/AArch64/AArch64Signal.cpp

106 lines
3.2 KiB
C++
Raw Normal View History

2024-08-21 03:58:03 +02:00
#include <stdafx.h>
#include "AArch64Signal.h"
namespace aarch64
{
// Some of the EC codes we care about
enum class EL1_exception_class
{
undefined = 0,
instr_abort_0 = 32, // PAGE_FAULT - Execute, change in EL
instr_abort_1 = 33, // PAGE_FAULT - Execute, same EL
data_abort_0 = 36, // PAGE_FAULT - Generic, causing change in EL (e.g kernel sig handler back to EL0)
data_abort_1 = 37, // PAGE_FAULT - Generic, no change in EL, e.g EL1 driver fault
illegal_execution = 14, // BUS_ERROR
unaligned_pc = 34, // BUS_ERROR
unaligned_sp = 38, // BUS_ERROR
breakpoint = 60, // BRK
};
2024-08-23 01:02:36 +02:00
#ifdef __linux__
2024-09-23 21:52:19 +02:00
constexpr u32 ESR_CTX_MAGIC = 0x45535201;
2024-08-21 03:58:03 +02:00
const aarch64_esr_ctx* find_EL1_esr_context(const ucontext_t* ctx)
{
u32 offset = 0;
const auto& mctx = ctx->uc_mcontext;
while ((offset + 4) < sizeof(mctx.__reserved))
{
2024-08-21 13:26:48 +02:00
const auto head = reinterpret_cast<const aarch64_cpu_ctx_block*>(&mctx.__reserved[offset]);
2024-08-21 03:58:03 +02:00
if (!head->magic)
{
// End of linked list
return nullptr;
}
if (head->magic == ESR_CTX_MAGIC)
{
return reinterpret_cast<const aarch64_esr_ctx*>(head);
}
offset += head->size;
}
return nullptr;
}
2024-08-23 01:02:36 +02:00
u64 _read_ESR_EL1(const ucontext_t* uctx)
2024-08-21 03:58:03 +02:00
{
auto esr_ctx = find_EL1_esr_context(uctx);
2024-08-23 01:02:36 +02:00
return esr_ctx ? esr_ctx->esr : 0;
}
2024-08-24 01:09:22 +02:00
#elif defined(__APPLE__)
u64 _read_ESR_EL1(const ucontext_t* uctx)
{
// Easy to read from mcontext
const auto darwin_ctx = reinterpret_cast<aarch64_darwin_mcontext64*>(uctx->uc_mcontext);
return darwin_ctx->es.ESR;
}
2024-08-23 01:02:36 +02:00
#else
2024-08-24 00:19:11 +02:00
u64 _read_ESR_EL1(const ucontext_t*)
2024-08-23 01:02:36 +02:00
{
// Unimplemented
return 0;
}
#endif
fault_reason decode_fault_reason(const ucontext_t* uctx)
{
auto esr = _read_ESR_EL1(uctx);
if (!esr)
2024-08-21 13:26:48 +02:00
{
2024-08-21 03:58:03 +02:00
return fault_reason::undefined;
}
// We don't really care about most of the register fields, but we can check for a few things.
2024-08-23 01:02:36 +02:00
const auto exception_class = (esr >> 26) & 0b111111;
2024-08-21 03:58:03 +02:00
switch (static_cast<EL1_exception_class>(exception_class))
{
case EL1_exception_class::breakpoint:
// Debug break
return fault_reason::breakpoint;
case EL1_exception_class::illegal_execution:
case EL1_exception_class::unaligned_pc:
case EL1_exception_class::unaligned_sp:
return fault_reason::illegal_instruction;
case EL1_exception_class::instr_abort_0:
case EL1_exception_class::instr_abort_1:
return fault_reason::instruction_execute;
case EL1_exception_class::data_abort_0:
case EL1_exception_class::data_abort_1:
// Page fault
break;
default:
return fault_reason::undefined;
}
// Check direction bit
2024-08-23 01:02:36 +02:00
const auto direction = (esr >> 6u) & 1u;
2024-08-21 03:58:03 +02:00
return direction ? fault_reason::data_write : fault_reason::data_read;
}
}