summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/k_hardware_timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/k_hardware_timer.cpp')
-rw-r--r--src/core/hle/kernel/k_hardware_timer.cpp75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp
new file mode 100644
index 000000000..afa777f9a
--- /dev/null
+++ b/src/core/hle/kernel/k_hardware_timer.cpp
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/k_hardware_timer.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/time_manager.h"
+
+namespace Kernel {
+
+void KHardwareTimer::Initialize() {
+ // Create the timing callback to register with CoreTiming.
+ m_event_type = Core::Timing::CreateEvent(
+ "KHardwareTimer::Callback",
+ [this](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) {
+ reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask();
+ return std::nullopt;
+ });
+}
+
+void KHardwareTimer::Finalize() {
+ this->DisableInterrupt();
+}
+
+void KHardwareTimer::DoTask() {
+ // Handle the interrupt.
+ {
+ KScopedSchedulerLock slk{m_kernel};
+ KScopedSpinLock lk(this->GetLock());
+
+ //! Ignore this event if needed.
+ if (!this->GetInterruptEnabled()) {
+ return;
+ }
+
+ // Disable the timer interrupt while we handle this.
+ this->DisableInterrupt();
+
+ if (const s64 next_time = this->DoInterruptTaskImpl(GetTick());
+ 0 < next_time && next_time <= m_wakeup_time) {
+ // We have a next time, so we should set the time to interrupt and turn the interrupt
+ // on.
+ this->EnableInterrupt(next_time);
+ }
+ }
+
+ // Clear the timer interrupt.
+ // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer,
+ // GetCurrentCoreId());
+}
+
+void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
+ this->DisableInterrupt();
+
+ m_wakeup_time = wakeup_time;
+ m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
+ m_event_type, reinterpret_cast<uintptr_t>(this),
+ true);
+}
+
+void KHardwareTimer::DisableInterrupt() {
+ m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
+ m_wakeup_time = std::numeric_limits<s64>::max();
+}
+
+s64 KHardwareTimer::GetTick() {
+ return m_kernel.System().CoreTiming().GetGlobalTimeNs().count();
+}
+
+bool KHardwareTimer::GetInterruptEnabled() {
+ return m_wakeup_time != std::numeric_limits<s64>::max();
+}
+
+} // namespace Kernel