diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp index 3c31124d8..253ade476 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp @@ -306,6 +306,10 @@ namespace ams::kern { } } + constexpr bool IsPermittedSvc(svc::SvcId id) const { + return (id < m_svc_access_flags.GetCount()) && m_svc_access_flags[id]; + } + constexpr bool IsPermittedInterrupt(u32 id) const { return (id < m_irq_access_flags.GetCount()) && m_irq_access_flags[id]; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 87b14b656..97429df05 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -194,6 +194,10 @@ namespace ams::kern { return m_attached_object != nullptr; } + constexpr bool IsPermittedSvc(svc::SvcId svc_id) const { + return m_capabilities.IsPermittedSvc(svc_id); + } + constexpr bool IsPermittedInterrupt(int32_t interrupt_id) const { return m_capabilities.IsPermittedInterrupt(interrupt_id); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index d1a327043..e6e0c97ae 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -285,6 +285,18 @@ namespace ams::kern::svc { *out = tick_count; } break; + case ams::svc::InfoType_IsSvcPermitted: + { + /* Verify the input handle is invalid. */ + R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); + + /* Verify the sub-type is valid. */ + R_UNLESS(info_subtype == svc::SvcId_SynchronizePreemptionState, svc::ResultInvalidCombination()); + + /* Get whether the svc is permitted. */ + *out = GetCurrentProcess().IsPermittedSvc(static_cast(info_subtype)); + } + break; case ams::svc::InfoType_MesosphereMeta: { /* Verify the handle is invalid. */ diff --git a/libraries/libstratosphere/source/os/impl/os_disable_counter.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_disable_counter.os.horizon.hpp new file mode 100644 index 000000000..47577cb15 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_disable_counter.os.horizon.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class CheckBusyMutexPermission { + public: + CheckBusyMutexPermission() { + /* In order to use the disable counter, we must support SynchronizePreemptionState. */ + u64 value; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), svc::InfoType_IsSvcPermitted, 0, svc::SvcId_SynchronizePreemptionState)); + + /* Verify that it's supported. */ + AMS_ABORT_UNLESS(value != 0); + } + }; + + ALWAYS_INLINE void CallCheckBusyMutexPermission() { + AMS_FUNCTION_LOCAL_STATIC(CheckBusyMutexPermission, s_check); + AMS_UNUSED(s_check); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp index d066b677a..8e7e10190 100644 --- a/libraries/libstratosphere/source/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include "os_disable_counter.os.horizon.hpp" namespace ams::os::impl { @@ -60,6 +61,9 @@ namespace ams::os::impl { AMS_ASSERT(cur_dc < std::numeric_limits::max()); const auto next_dc = cur_dc + 1; + /* Check that we're allowed to use busy mutexes. */ + CallCheckBusyMutexPermission(); + /* Get pointer to our value. */ u32 * const p = std::addressof(m_value); @@ -101,6 +105,9 @@ namespace ams::os::impl { AMS_ASSERT(cur_dc < std::numeric_limits::max()); const auto next_dc = cur_dc + 1; + /* Check that we're allowed to use busy mutexes. */ + CallCheckBusyMutexPermission(); + /* Get pointer to our value. */ u32 * const p = std::addressof(m_value); diff --git a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp index 1e47e62c0..9d74be316 100644 --- a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include "os_disable_counter.os.horizon.hpp" namespace ams::os::impl { @@ -80,6 +81,9 @@ namespace ams::os::impl { AMS_ABORT_UNLESS(cur_dc < std::numeric_limits::max()); const auto next_dc = cur_dc + 1; + /* Check that we're allowed to use busy mutexes. */ + CallCheckBusyMutexPermission(); + /* Get pointer to our value. */ u32 * const p = std::addressof(m_value); @@ -162,6 +166,9 @@ namespace ams::os::impl { AMS_ABORT_UNLESS(cur_dc < std::numeric_limits::max()); const auto next_dc = cur_dc + 1; + /* Check that we're allowed to use busy mutexes. */ + CallCheckBusyMutexPermission(); + /* Get pointer to our value. */ u32 * const p = std::addressof(m_value); diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 7692b7ebb..d1aa25edf 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -165,6 +165,7 @@ namespace ams::svc { InfoType_IsApplication = 23, InfoType_FreeThreadCount = 24, InfoType_ThreadTickCount = 25, + InfoType_IsSvcPermitted = 26, InfoType_MesosphereMeta = 65000, InfoType_MesosphereCurrentProcess = 65001,