From 9e25c588996a41392e40683a99d3e73f81fabb96 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 30 Apr 2025 19:57:45 -0700 Subject: [PATCH] kern: adjust system registers during exception handling on MTE-violation or kernel address fault --- .../arch/arm64/kern_exception_handlers.cpp | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp b/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp index 0fc25c741..b745d5ab3 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp @@ -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: