kern: adjust system registers during exception handling on MTE-violation or kernel address fault

This commit is contained in:
Michael Scire 2025-04-30 19:57:45 -07:00
parent 480a66e06b
commit 9e25c58899

View file

@ -109,12 +109,28 @@ namespace ams::kern::arch::arm64 {
return insn;
}
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
void HandleUserException(KExceptionContext *context, u64 raw_esr, u64 raw_far, u64 afsr0, u64 afsr1, u32 data) {
/* Pre-process exception registers as needed. */
u64 esr = raw_esr;
u64 far = raw_far;
const u64 ec = (esr >> 26) & 0x3F;
if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) {
/* Adjust registers if a memory tagging exception has occurred. */
/* TODO: How would we perform this check using named register accesses? */
if ((esr & 0x43F) == 0x410) {
/* Clear the faulting register on memory tagging exception. */
far = 0;
} else {
/* If the faulting address is a kernel address, set ISFC = 4. */
if (far >= ams::svc::AddressMemoryRegion39Size) {
esr = (esr & 0xFFFFFFC0) | 4;
}
}
}
KProcess &cur_process = GetCurrentProcess();
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
const u64 ec = (esr >> 26) & 0x3F;
/* In the event that we return from this exception, we want SPSR.SS set so that we advance an instruction if single-stepping. */
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
context->psr |= (1ul << 21);
@ -165,7 +181,7 @@ namespace ams::kern::arch::arm64 {
}
/* Save the debug parameters to the current thread. */
GetCurrentThread().SaveDebugParams(far, esr, data);
GetCurrentThread().SaveDebugParams(raw_far, raw_esr, data);
/* Get the exception type. */
u32 type;
@ -387,7 +403,6 @@ namespace ams::kern::arch::arm64 {
ams::svc::aarch32::ExceptionInfo info32;
} info = {};
const bool is_aarch64 = (e_ctx->psr & 0x10) == 0;
if (is_aarch64) {
/* We're 64-bit. */
@ -432,9 +447,25 @@ namespace ams::kern::arch::arm64 {
uintptr_t far, esr, data;
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
/* Pre-process exception registers as needed. */
const u64 ec = (esr >> 26) & 0x3F;
if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) {
/* Adjust registers if a memory tagging exception has occurred. */
/* TODO: How would we perform this check using named register accesses? */
if ((esr & 0x43F) == 0x410) {
/* Clear the faulting register on memory tagging exception. */
far = 0;
} else {
/* If the faulting address is a kernel address, set ISFC = 4. */
if (far >= ams::svc::AddressMemoryRegion39Size) {
esr = (esr & 0xFFFFFFC0) | 4;
}
}
}
/* Collect additional information based on the ec. */
uintptr_t params[3] = {};
switch ((esr >> 26) & 0x3F) {
switch (ec) {
case EsrEc_Unknown:
case EsrEc_IllegalExecution:
case EsrEc_BkptInstruction: