diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_auto_object_container.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_auto_object_container.hpp index 3d501bdf1..f89839e8c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_auto_object_container.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_auto_object_container.hpp @@ -23,7 +23,7 @@ namespace ams::kern { class KAutoObjectWithListContainer { NON_COPYABLE(KAutoObjectWithListContainer); NON_MOVEABLE(KAutoObjectWithListContainer); - private: + public: using ListType = util::IntrusiveRedBlackTreeMemberTraits<&KAutoObjectWithList::list_node>::TreeType; public: class ListAccessor : public KScopedLightLock { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 9cce690b2..6a13f6a50 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -522,6 +522,7 @@ namespace ams::kern { return ConditionVariableThreadTreeTraits::IsValid(); } + static KThread *GetThreadFromId(u64 thread_id); static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count); using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/libraries/libmesosphere/include/mesosphere/svc/kern_svc_results.hpp b/libraries/libmesosphere/include/mesosphere/svc/kern_svc_results.hpp index 4b84670ae..a1aa17d2c 100644 --- a/libraries/libmesosphere/include/mesosphere/svc/kern_svc_results.hpp +++ b/libraries/libmesosphere/include/mesosphere/svc/kern_svc_results.hpp @@ -71,6 +71,7 @@ namespace ams::kern::svc { /* 260 */ using ::ams::svc::ResultMessageTooLarge; /* 517 */ using ::ams::svc::ResultInvalidProcessId; + /* 518 */ using ::ams::svc::ResultInvalidThreadId; /* 520 */ using ::ams::svc::ResultProcessTerminated; } diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 7d6be53bb..ae84126fa 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -1190,6 +1190,41 @@ namespace ams::kern { return std::addressof(this->GetContext()); } + KThread *KThread::GetThreadFromId(u64 thread_id) { + /* Lock the list. */ + KThread::ListAccessor accessor; + const auto end = accessor.end(); + + /* Define helper object to find the thread. */ + class IdObjectHelper : public KAutoObjectWithListContainer::ListType::value_type { + private: + u64 id; + public: + constexpr explicit IdObjectHelper(u64 id) : id(id) { /* ... */ } + virtual u64 GetId() const override { return this->id; } + }; + + /* Find the object with the right id. */ + const auto it = accessor.find(IdObjectHelper(thread_id)); + + /* Check to make sure we found the thread. */ + if (it == end) { + return nullptr; + } + + /* Get the thread. */ + KThread *thread = static_cast(std::addressof(*it)); + + /* Open the thread. */ + if (AMS_LIKELY(thread->Open())) { + MESOSPHERE_ASSERT(thread->GetId() == thread_id); + return thread; + } + + /* We failed to find the thread. */ + return nullptr; + } + Result KThread::GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer out_thread_ids, s32 max_out_count) { /* Lock the list. */ KThread::ListAccessor accessor; diff --git a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp index 81a4e9d7f..6df5aa244 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_debug.cpp @@ -246,6 +246,105 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { + /* Get the debug object. */ + KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject(debug_handle); + R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); + + /* Get the thread from its id. */ + KScopedAutoObject thread = KThread::GetThreadFromId(thread_id); + R_UNLESS(thread.IsNotNull(), svc::ResultInvalidThreadId()); + + /* Get the process from the debug object. */ + KScopedAutoObject process = debug->GetProcess(); + R_UNLESS(process.IsNotNull(), svc::ResultProcessTerminated()); + + /* Verify that the process is the thread's parent. */ + R_UNLESS(process.GetPointerUnsafe() == thread->GetOwnerProcess(), svc::ResultInvalidThreadId()); + + /* Get the parameter. */ + switch (param) { + case ams::svc::DebugThreadParam_Priority: + { + /* Get the priority. */ + *out_32 = thread->GetPriority(); + } + break; + case ams::svc::DebugThreadParam_State: + { + /* Get the thread state and suspend status. */ + KThread::ThreadState state; + bool suspended_user; + bool suspended_debug; + { + KScopedSchedulerLock sl; + + state = thread->GetState(); + suspended_user = thread->IsSuspendRequested(KThread::SuspendType_Thread); + suspended_debug = thread->IsSuspendRequested(KThread::SuspendType_Debug); + } + + /* Set the suspend flags. */ + *out_32 = 0; + if (suspended_user) { + *out_32 |= ams::svc::ThreadSuspend_User; + } + if (suspended_debug) { + *out_32 |= ams::svc::ThreadSuspend_Debug; + } + + /* Set the state. */ + switch (state) { + case KThread::ThreadState_Initialized: + { + *out_64 = ams::svc::ThreadState_Initializing; + } + break; + case KThread::ThreadState_Waiting: + { + *out_64 = ams::svc::ThreadState_Waiting; + } + break; + case KThread::ThreadState_Runnable: + { + *out_64 = ams::svc::ThreadState_Running; + } + break; + case KThread::ThreadState_Terminated: + { + *out_64 = ams::svc::ThreadState_Terminated; + } + break; + default: + return svc::ResultInvalidState(); + } + } + break; + case ams::svc::DebugThreadParam_IdealCore: + { + /* Get the ideal core. */ + *out_32 = thread->GetIdealCore(); + } + break; + case ams::svc::DebugThreadParam_CurrentCore: + { + /* Get the current core. */ + *out_32 = thread->GetActiveCore(); + } + break; + case ams::svc::DebugThreadParam_AffinityMask: + { + /* Get the affinity mask. */ + *out_32 = thread->GetAffinityMask().GetAffinityMask(); + } + break; + default: + return ams::svc::ResultInvalidEnumValue(); + } + + return ResultSuccess(); + } + } /* ============================= 64 ABI ============================= */ @@ -299,7 +398,7 @@ namespace ams::kern::svc { } Result GetDebugThreadParam64(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { - MESOSPHERE_PANIC("Stubbed SvcGetDebugThreadParam64 was called."); + return GetDebugThreadParam(out_64, out_32, debug_handle, thread_id, param); } /* ============================= 64From32 ABI ============================= */ @@ -353,7 +452,7 @@ namespace ams::kern::svc { } Result GetDebugThreadParam64From32(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { - MESOSPHERE_PANIC("Stubbed SvcGetDebugThreadParam64From32 was called."); + return GetDebugThreadParam(out_64, out_32, debug_handle, thread_id, param); } } diff --git a/libraries/libvapours/include/vapours/results/svc_results.hpp b/libraries/libvapours/include/vapours/results/svc_results.hpp index 1ac86e893..d07d50e5e 100644 --- a/libraries/libvapours/include/vapours/results/svc_results.hpp +++ b/libraries/libvapours/include/vapours/results/svc_results.hpp @@ -74,6 +74,7 @@ namespace ams::svc { R_DEFINE_ERROR_RESULT(MessageTooLarge, 260); R_DEFINE_ERROR_RESULT(InvalidProcessId, 517); + R_DEFINE_ERROR_RESULT(InvalidThreadId, 518); R_DEFINE_ERROR_RESULT(ProcessTerminated, 520); }