From aae3c789f2f968942309ae06da63f4e449872d94 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Feb 2020 20:42:21 -0800 Subject: [PATCH] kern: implement unsuspension of init threads --- .../arch/arm64/kern_k_process_page_table.hpp | 5 +++ .../arm64/kern_k_supervisor_page_table.hpp | 14 ++++++- .../include/mesosphere/kern_k_process.hpp | 20 ++++++++++ .../include/mesosphere/kern_k_thread.hpp | 4 ++ .../include/mesosphere/kern_slab_helpers.hpp | 6 +++ .../arm64/kern_k_supervisor_page_table.cpp | 8 ---- .../libmesosphere/source/kern_k_process.cpp | 31 ++++++++++++++++ .../libmesosphere/source/kern_k_scheduler.cpp | 6 +-- .../libmesosphere/source/kern_k_thread.cpp | 37 +++++++++++++++++-- libraries/libmesosphere/source/kern_main.cpp | 3 +- 10 files changed, 117 insertions(+), 17 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index d7db6e9c7..0639a11c9 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -25,6 +25,11 @@ namespace ams::kern::arch::arm64 { public: constexpr KProcessPageTable() : page_table() { /* ... */ } + void Activate(u64 id) { + /* Activate the page table with the specified contextidr. */ + this->page_table.Activate(id); + } + Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) { return this->page_table.InitializeForProcess(id, as_type, enable_aslr, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager); } diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index 4061c78e9..0a1f71872 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -28,7 +28,19 @@ namespace ams::kern::arch::arm64 { constexpr KSupervisorPageTable() : page_table(), ttbr0() { /* ... */ } NOINLINE void Initialize(s32 core_id); - NOINLINE void Activate(); + + void Activate() { + /* Activate, using process id = 0xFFFFFFFF */ + this->page_table.Activate(0xFFFFFFFF); + } + + void ActivateForInit() { + this->Activate(); + + /* Invalidate entire TLB. */ + cpu::InvalidateEntireTlb(); + } + void Finalize(s32 core_id); Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 404e7330f..7c35d8963 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -149,6 +149,11 @@ namespace ams::kern { constexpr KResourceLimit *GetResourceLimit() const { return this->resource_limit; } + bool ReserveResource(ams::svc::LimitableResource which, s64 value); + bool ReserveResource(ams::svc::LimitableResource which, s64 value, s64 timeout); + void ReleaseResource(ams::svc::LimitableResource which, s64 value); + void ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint); + constexpr KProcessPageTable &GetPageTable() { return this->page_table; } constexpr const KProcessPageTable &GetPageTable() const { return this->page_table; } @@ -158,6 +163,9 @@ namespace ams::kern { Result CreateThreadLocalRegion(KProcessAddress *out); void *GetThreadLocalRegionPointer(KProcessAddress addr); + void AddCpuTime(s64 diff) { this->cpu_time += diff; } + void IncrementScheduledCount() { ++this->schedule_count; } + void IncrementThreadCount(); void DecrementThreadCount(); @@ -167,6 +175,18 @@ namespace ams::kern { Result Run(s32 priority, size_t stack_size); void SetPreemptionState(); + + static void Switch(KProcess *cur_process, KProcess *next_process) { + /* Set the current process pointer. */ + SetCurrentProcess(next_process); + + /* Update the current page table. */ + if (next_process) { + next_process->GetPageTable().Activate(next_process->GetProcessId()); + } else { + Kernel::GetKernelPageTable().Activate(); + } + } public: /* Overridden parent functions. */ virtual bool IsInitialized() const override { return this->is_initialized; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index efa2bc312..7acd9a209 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -201,6 +201,8 @@ namespace ams::kern { static Result InitializeUserThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner) { return InitializeThread(thread, func, arg, user_stack_top, prio, core, owner, ThreadType_User); } + + static void ResumeThreadsSuspendedForInit(); private: StackParameters &GetStackParameters() { return *(reinterpret_cast(this->kernel_stack_top) - 1); @@ -280,6 +282,7 @@ namespace ams::kern { constexpr uintptr_t GetConditionVariableKey() const { return this->condvar_key; } + constexpr s32 GetIdealCore() const { return this->ideal_core_id; } constexpr s32 GetActiveCore() const { return this->core_id; } constexpr void SetActiveCore(s32 core) { this->core_id = core; } constexpr s32 GetPriority() const { return this->priority; } @@ -332,6 +335,7 @@ namespace ams::kern { constexpr u32 GetSuspendFlags() const { return this->suspend_allowed_flags & this->suspend_request_flags; } constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; } void RequestSuspend(SuspendType type); + void Resume(SuspendType type); void TrySuspend(); void Continue(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp index a5155dea5..b34150cbd 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp @@ -64,6 +64,12 @@ namespace ams::kern { static ALWAYS_INLINE void Free(Derived *obj) { s_slab_heap.Free(obj); } + public: + class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { + public: + ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ } + ALWAYS_INLINE ~ListAccessor() { /* ... */ } + }; public: constexpr KAutoObjectWithSlabHeapAndContainer() : Base() { /* ... */ } virtual ~KAutoObjectWithSlabHeapAndContainer() { /* ... */ } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp index 7539cb041..d8a75c7dd 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp @@ -39,14 +39,6 @@ namespace ams::kern::arch::arm64 { } } - void KSupervisorPageTable::Activate() { - /* Initialize, using process id = 0xFFFFFFFF */ - this->page_table.Initialize(0xFFFFFFFF); - - /* Invalidate entire TLB. */ - cpu::InvalidateEntireTlb(); - } - void KSupervisorPageTable::Finalize(s32 core_id) { MESOSPHERE_TODO_IMPLEMENT(); } diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 6a2decac1..9d45c0d35 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -222,6 +222,34 @@ namespace ams::kern { return static_cast(tlp->GetPointer()) + (GetInteger(addr) & (PageSize - 1)); } + bool KProcess::ReserveResource(ams::svc::LimitableResource which, s64 value) { + if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { + return rl->Reserve(which, value); + } else { + return true; + } + } + + bool KProcess::ReserveResource(ams::svc::LimitableResource which, s64 value, s64 timeout) { + if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { + return rl->Reserve(which, value, timeout); + } else { + return true; + } + } + + void KProcess::ReleaseResource(ams::svc::LimitableResource which, s64 value) { + if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { + rl->Release(which, value); + } + } + + void KProcess::ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint) { + if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { + rl->Release(which, value, hint); + } + } + void KProcess::IncrementThreadCount() { MESOSPHERE_ASSERT(this->num_threads >= 0); ++this->num_created_threads; @@ -335,6 +363,9 @@ namespace ams::kern { stack_guard.Cancel(); mem_reservation.Commit(); + /* Note for debug that we're running a new process. */ + MESOSPHERE_LOG("KProcess::Run() pid=%ld name=%-12s thread=%ld affinity=0x%lx ideal_core=%d active_core=%d\n", this->process_id, this->name, main_thread->GetId(), main_thread->GetAffinityMask().GetAffinityMask(), main_thread->GetIdealCore(), main_thread->GetActiveCore()); + return ResultSuccess(); } diff --git a/libraries/libmesosphere/source/kern_k_scheduler.cpp b/libraries/libmesosphere/source/kern_k_scheduler.cpp index 22677e0d9..97dcb1165 100644 --- a/libraries/libmesosphere/source/kern_k_scheduler.cpp +++ b/libraries/libmesosphere/source/kern_k_scheduler.cpp @@ -38,7 +38,7 @@ namespace ams::kern { ALWAYS_INLINE void IncrementScheduledCount(KThread *thread) { if (KProcess *parent = thread->GetOwnerProcess(); parent != nullptr) { - MESOSPHERE_TODO("parent->IncrementScheduledCount();"); + parent->IncrementScheduledCount(); } } @@ -234,7 +234,7 @@ namespace ams::kern { const s64 tick_diff = cur_tick - prev_tick; cur_thread->AddCpuTime(tick_diff); if (cur_process != nullptr) { - MESOSPHERE_TODO("cur_process->AddCpuTime(tick_diff);"); + cur_process->AddCpuTime(tick_diff); } this->last_context_switch_time = cur_tick; @@ -252,7 +252,7 @@ namespace ams::kern { /* Switch the current process, if we're switching processes. */ if (KProcess *next_process = next_thread->GetOwnerProcess(); next_process != cur_process) { - MESOSPHERE_TODO("KProcess::Switch"); + KProcess::Switch(cur_process, next_process); } /* Set the new thread. */ diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 44b580c22..0bef0856d 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -232,12 +232,23 @@ namespace ams::kern { void KThread::PostDestroy(uintptr_t arg) { KProcess *owner = reinterpret_cast(arg & ~1ul); const bool resource_limit_release_hint = (arg & 1); + const s64 hint_value = (resource_limit_release_hint ? 0 : 1); if (owner != nullptr) { - MESOSPHERE_TODO("Release from owner resource limit."); - (void)(resource_limit_release_hint); + owner->ReleaseResource(ams::svc::LimitableResource_ThreadCountMax, 1, hint_value); owner->Close(); } else { - MESOSPHERE_TODO("Release from system resource limit."); + Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_ThreadCountMax, 1, hint_value); + } + } + + void KThread::ResumeThreadsSuspendedForInit() { + KThread::ListAccessor list_accessor; + { + KScopedSchedulerLock sl; + + for (auto &thread : list_accessor) { + static_cast(thread).Resume(SuspendType_Init); + } } } @@ -310,6 +321,8 @@ namespace ams::kern { Result KThread::SetPriorityToIdle() { MESOSPHERE_ASSERT_THIS(); + KScopedSchedulerLock sl; + /* Change both our priorities to the idle thread priority. */ const s32 old_priority = this->priority; this->priority = IdleThreadPriority; @@ -325,12 +338,28 @@ namespace ams::kern { KScopedSchedulerLock lk; /* Note the request in our flags. */ - this->suspend_request_flags |= (1 << (ThreadState_SuspendShift + type)); + this->suspend_request_flags |= (1u << (ThreadState_SuspendShift + type)); /* Try to perform the suspend. */ this->TrySuspend(); } + void KThread::Resume(SuspendType type) { + MESOSPHERE_ASSERT_THIS(); + + KScopedSchedulerLock sl; + + /* Clear the request in our flags. */ + this->suspend_request_flags &= ~(1u << (ThreadState_SuspendShift + type)); + + /* Update our state. */ + const ThreadState old_state = this->thread_state; + this->thread_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); + if (this->thread_state != old_state) { + KScheduler::OnThreadStateChanged(this, old_state); + } + } + void KThread::TrySuspend() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/kern_main.cpp b/libraries/libmesosphere/source/kern_main.cpp index 762a841e2..5a9abdf9c 100644 --- a/libraries/libmesosphere/source/kern_main.cpp +++ b/libraries/libmesosphere/source/kern_main.cpp @@ -122,7 +122,8 @@ namespace ams::kern { /* We're done initializing! */ Kernel::SetState(Kernel::State::Initialized); - MESOSPHERE_TODO("KThread::ResumeThreadsSuspendedForInit();"); + /* Resume all threads suspended while we initialized. */ + KThread::ResumeThreadsSuspendedForInit(); } cpu::SynchronizeAllCores();