diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp index 6b6d16dd7..ae5b60517 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp @@ -105,35 +105,48 @@ namespace ams::kern::arch::arm64 { Result UnbindLocal(s32 irq); Result ClearGlobal(s32 irq); Result ClearLocal(s32 irq); - public: - static ALWAYS_INLINE u32 DisableInterrupts() { + private: + [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledState() { u64 intr_state; - __asm__ __volatile__("mrs %[intr_state], daif\n" - "msr daifset, #2" + __asm__ __volatile__("mrs %[intr_state], daif\n" + "ubfx %[intr_state], %[intr_state], #7, #1" : [intr_state]"=r"(intr_state) :: "memory"); return intr_state; } + public: + static ALWAYS_INLINE void EnableInterrupts() { + __asm__ __volatile__("msr daifclr, #2" ::: "memory"); + } - static ALWAYS_INLINE u32 EnableInterrupts() { - u64 intr_state; - __asm__ __volatile__("mrs %[intr_state], daif\n" - "msr daifclr, #2" - : [intr_state]"=r"(intr_state) - :: "memory"); + static ALWAYS_INLINE void DisableInterrupts() { + __asm__ __volatile__("msr daifset, #2" ::: "memory"); + } + + [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndDisableInterrupts() { + const auto intr_state = GetInterruptsEnabledState(); + DisableInterrupts(); + return intr_state; + } + + [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndEnableInterrupts() { + const auto intr_state = GetInterruptsEnabledState(); + EnableInterrupts(); return intr_state; } static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) { - u64 cur_state; - __asm__ __volatile__("mrs %[cur_state], daif" : [cur_state]"=r"(cur_state)); - __asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"((cur_state & ~0x80ul) | (intr_state & 0x80))); + u64 tmp; + __asm__ __volatile__("mrs %[tmp], daif\n" + "bfi %[tmp], %[intr_state], #7, #1\n" + "msr daif, %[tmp]" + : [tmp]"=&r"(tmp) + : [intr_state]"r"(intr_state) + : "memory"); } static ALWAYS_INLINE bool AreInterruptsEnabled() { - u64 intr_state; - __asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state)); - return (intr_state & 0x80) == 0; + return GetInterruptsEnabledState() == 0; } }; diff --git a/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp index e630d3c83..047ea960d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp @@ -41,7 +41,7 @@ namespace ams::kern { private: u32 m_prev_intr_state; public: - ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ } + ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndDisableInterrupts()) { /* ... */ } ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } }; @@ -51,7 +51,7 @@ namespace ams::kern { private: u32 m_prev_intr_state; public: - ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ } + ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndEnableInterrupts()) { /* ... */ } ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } }; diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_manager.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_manager.cpp index 64c48c039..9ac764dd7 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_manager.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_manager.cpp @@ -201,7 +201,7 @@ namespace ams::kern::arch::arm64 { if (user_mode) { KThread *cur_thread = GetCurrentThreadPointer(); if (cur_thread->IsTerminationRequested()) { - KScopedInterruptEnable ei; + EnableInterrupts(); cur_thread->Exit(); } } @@ -212,13 +212,14 @@ namespace ams::kern::arch::arm64 { R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); - KScopedInterruptDisable di; - if (KInterruptController::IsGlobal(irq)) { + KScopedInterruptDisable di; KScopedSpinLock lk(this->GetGlobalInterruptLock()); return this->BindGlobal(handler, irq, core_id, priority, manual_clear, level); } else { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); + + KScopedInterruptDisable di; return this->BindLocal(handler, irq, priority, manual_clear); } } @@ -228,13 +229,16 @@ namespace ams::kern::arch::arm64 { R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); - KScopedInterruptDisable di; if (KInterruptController::IsGlobal(irq)) { + KScopedInterruptDisable di; + KScopedSpinLock lk(this->GetGlobalInterruptLock()); return this->UnbindGlobal(irq); } else { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); + + KScopedInterruptDisable di; return this->UnbindLocal(irq); } } @@ -244,13 +248,15 @@ namespace ams::kern::arch::arm64 { R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); - KScopedInterruptDisable di; if (KInterruptController::IsGlobal(irq)) { + KScopedInterruptDisable di; KScopedSpinLock lk(this->GetGlobalInterruptLock()); return this->ClearGlobal(irq); } else { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); + + KScopedInterruptDisable di; return this->ClearLocal(irq); } }