k_hardware_timer.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/core.h"
  4. #include "core/core_timing.h"
  5. #include "core/hle/kernel/k_hardware_timer.h"
  6. #include "core/hle/kernel/k_scheduler.h"
  7. namespace Kernel {
  8. void KHardwareTimer::Initialize() {
  9. // Create the timing callback to register with CoreTiming.
  10. m_event_type = Core::Timing::CreateEvent(
  11. "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) {
  12. reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask();
  13. return std::nullopt;
  14. });
  15. }
  16. void KHardwareTimer::Finalize() {
  17. m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
  18. m_wakeup_time = std::numeric_limits<s64>::max();
  19. m_event_type.reset();
  20. }
  21. void KHardwareTimer::DoTask() {
  22. // Handle the interrupt.
  23. {
  24. KScopedSchedulerLock slk{m_kernel};
  25. KScopedSpinLock lk(this->GetLock());
  26. //! Ignore this event if needed.
  27. if (!this->GetInterruptEnabled()) {
  28. return;
  29. }
  30. // Disable the timer interrupt while we handle this.
  31. // Not necessary due to core timing already having popped this event to call it.
  32. // this->DisableInterrupt();
  33. m_wakeup_time = std::numeric_limits<s64>::max();
  34. if (const s64 next_time = this->DoInterruptTaskImpl(GetTick());
  35. 0 < next_time && next_time <= m_wakeup_time) {
  36. // We have a next time, so we should set the time to interrupt and turn the interrupt
  37. // on.
  38. this->EnableInterrupt(next_time);
  39. }
  40. }
  41. // Clear the timer interrupt.
  42. // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer,
  43. // GetCurrentCoreId());
  44. }
  45. void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
  46. this->DisableInterrupt();
  47. m_wakeup_time = wakeup_time;
  48. m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time},
  49. m_event_type, reinterpret_cast<uintptr_t>(this),
  50. true);
  51. }
  52. void KHardwareTimer::DisableInterrupt() {
  53. m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
  54. reinterpret_cast<uintptr_t>(this));
  55. m_wakeup_time = std::numeric_limits<s64>::max();
  56. }
  57. s64 KHardwareTimer::GetTick() const {
  58. return m_kernel.System().CoreTiming().GetGlobalTimeNs().count();
  59. }
  60. bool KHardwareTimer::GetInterruptEnabled() {
  61. return m_wakeup_time != std::numeric_limits<s64>::max();
  62. }
  63. } // namespace Kernel