diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp index f69e55891..a7ebf8463 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp @@ -19,15 +19,11 @@ namespace ams::kern::arch::arm64 { - namespace impl { - - class KHardwareTimerInterruptTask; - - } - - class KHardwareTimer : public KHardwareTimerBase { + class KHardwareTimer : public KInterruptTask, public KHardwareTimerBase { + private: + s64 maximum_time; public: - constexpr KHardwareTimer() : KHardwareTimerBase() { /* ... */ } + constexpr KHardwareTimer() : KInterruptTask(), KHardwareTimerBase(), maximum_time(std::numeric_limits::max()) { /* ... */ } public: /* Public API. */ NOINLINE void Initialize(s32 core_id); @@ -42,13 +38,12 @@ namespace ams::kern::arch::arm64 { KScopedSpinLock lk(this->GetLock()); if (this->RegisterAbsoluteTaskImpl(task, task_time)) { - SetCompareValue(task_time); - EnableInterrupt(); + if (task_time <= this->maximum_time) { + SetCompareValue(task_time); + EnableInterrupt(); + } } } - private: - friend class impl::KHardwareTimerInterruptTask; - NOINLINE void DoInterruptTask(); private: /* Hardware register accessors. */ static ALWAYS_INLINE void InitializeGlobalTimer() { @@ -88,7 +83,13 @@ namespace ams::kern::arch::arm64 { static ALWAYS_INLINE void SetCompareValue(s64 value) { cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(static_cast(value)).Store(); } + public: + virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { + MESOSPHERE_UNUSED(interrupt_id); + return this; + } + virtual void DoTask() override; }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp index d9d4fd32d..639bc631d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_core_local_region.hpp @@ -29,7 +29,6 @@ namespace ams::kern { KCurrentContext current; KScheduler scheduler; KInterruptTaskManager interrupt_task_manager; - KHardwareTimer hardware_timer; /* Everything after this point is for debugging. */ /* Retail kernel doesn't even consistently update these fields. */ u64 num_sw_interrupts; diff --git a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp index 67e781721..c5d8525fd 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp @@ -74,6 +74,7 @@ namespace ams::kern { static KUnsafeMemory s_unsafe_memory; static KWorkerTaskManager s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; static KInterruptManager s_interrupt_manager; + static KHardwareTimer s_hardware_timers[cpu::NumCores]; private: static ALWAYS_INLINE KCoreLocalContext &GetCoreLocalContext() { return reinterpret_cast(cpu::GetCoreLocalRegionAddress())->current.context; @@ -114,7 +115,11 @@ namespace ams::kern { } static ALWAYS_INLINE KHardwareTimer &GetHardwareTimer() { - return GetCoreLocalContext(GetCurrentCoreId()).hardware_timer; + return s_hardware_timers[GetCurrentCoreId()]; + } + + static ALWAYS_INLINE KHardwareTimer &GetHardwareTimer(s32 core_id) { + return s_hardware_timers[core_id]; } static ALWAYS_INLINE KResourceLimit &GetSystemResourceLimit() { diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp index 40420496f..280a66f88 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp @@ -17,41 +17,15 @@ namespace ams::kern::arch::arm64 { - namespace impl { - - class KHardwareTimerInterruptTask : public KInterruptTask { - public: - constexpr KHardwareTimerInterruptTask() : KInterruptTask() { /* ... */ } - - virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { - MESOSPHERE_UNUSED(interrupt_id); - return this; - } - - virtual void DoTask() override { - Kernel::GetHardwareTimer().DoInterruptTask(); - } - }; - - } - - namespace { - - /* One global hardware timer interrupt task per core. */ - impl::KHardwareTimerInterruptTask g_hardware_timer_interrupt_tasks[cpu::NumCores]; - - ALWAYS_INLINE auto *GetHardwareTimerInterruptTask(s32 core_id) { - return std::addressof(g_hardware_timer_interrupt_tasks[core_id]); - } - - } - void KHardwareTimer::Initialize(s32 core_id) { /* Setup the global timer for the core. */ InitializeGlobalTimer(); + /* Set maximum time. */ + this->maximum_time = static_cast(std::min(std::numeric_limits::max(), cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor().GetCompareValue())); + /* Bind the interrupt task for this core. */ - Kernel::GetInterruptManager().BindHandler(GetHardwareTimerInterruptTask(core_id), KInterruptName_NonSecurePhysicalTimer, core_id, KInterruptController::PriorityLevel_Timer, true, true); + Kernel::GetInterruptManager().BindHandler(std::addressof(Kernel::GetHardwareTimer(core_id)), KInterruptName_NonSecurePhysicalTimer, core_id, KInterruptController::PriorityLevel_Timer, true, true); } void KHardwareTimer::Finalize() { @@ -59,7 +33,7 @@ namespace ams::kern::arch::arm64 { StopTimer(); } - void KHardwareTimer::DoInterruptTask() { + void KHardwareTimer::DoTask() { /* Handle the interrupt. */ { KScopedSchedulerLock slk; @@ -67,7 +41,7 @@ namespace ams::kern::arch::arm64 { /* Disable the timer interrupt while we handle this. */ DisableInterrupt(); - if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); next_time > 0) { + if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); 0 < next_time && next_time <= this->maximum_time) { /* We have a next time, so we should set the time to interrupt and turn the interrupt on. */ SetCompareValue(next_time); EnableInterrupt(); diff --git a/mesosphere/kernel/source/kern_kernel_instantiations.cpp b/mesosphere/kernel/source/kern_kernel_instantiations.cpp index 818dc4254..c5ffea0a4 100644 --- a/mesosphere/kernel/source/kern_kernel_instantiations.cpp +++ b/mesosphere/kernel/source/kern_kernel_instantiations.cpp @@ -30,6 +30,7 @@ namespace ams::kern { constinit KUnsafeMemory Kernel::s_unsafe_memory; constinit KWorkerTaskManager Kernel::s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; constinit KInterruptManager Kernel::s_interrupt_manager; + constinit KHardwareTimer Kernel::s_hardware_timers[cpu::NumCores]; namespace {