mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-06-21 19:12:42 +02:00
95 lines
3.6 KiB
C++
95 lines
3.6 KiB
C++
/*
|
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#pragma once
|
|
#include <mesosphere/kern_select_cpu.hpp>
|
|
#include <mesosphere/kern_k_hardware_timer_base.hpp>
|
|
|
|
namespace ams::kern::arm64 {
|
|
|
|
namespace impl {
|
|
|
|
class KHardwareTimerInterruptTask;
|
|
|
|
}
|
|
|
|
class KHardwareTimer : public KHardwareTimerBase {
|
|
public:
|
|
constexpr KHardwareTimer() : KHardwareTimerBase() { /* ... */ }
|
|
public:
|
|
/* Public API. */
|
|
NOINLINE void Initialize(s32 core_id);
|
|
NOINLINE void Finalize();
|
|
|
|
static s64 GetTick() {
|
|
return GetCount();
|
|
}
|
|
|
|
void RegisterAbsoluteTask(KTimerTask *task, s64 task_time) {
|
|
KScopedDisableDispatch dd;
|
|
KScopedSpinLock lk(this->GetLock());
|
|
|
|
if (this->RegisterAbsoluteTaskImpl(task, task_time)) {
|
|
SetCompareValue(task_time);
|
|
EnableInterrupt();
|
|
}
|
|
}
|
|
private:
|
|
friend class impl::KHardwareTimerInterruptTask;
|
|
NOINLINE void DoInterruptTask();
|
|
private:
|
|
/* Hardware register accessors. */
|
|
static ALWAYS_INLINE void InitializeGlobalTimer() {
|
|
/* Set kernel control. */
|
|
cpu::CounterTimerKernelControlRegisterAccessor(0).SetEl0PctEn(true).Store();
|
|
|
|
/* Disable the physical timer. */
|
|
cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(false).SetIMask(false).Store();
|
|
|
|
/* Set the compare value to the maximum. */
|
|
cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(std::numeric_limits<u64>::max()).Store();
|
|
|
|
/* Enable the physical timer, with interrupt masked. */
|
|
cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(true).Store();
|
|
}
|
|
|
|
static ALWAYS_INLINE void EnableInterrupt() {
|
|
cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(false).Store();
|
|
}
|
|
|
|
static ALWAYS_INLINE void DisableInterrupt() {
|
|
cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(true).Store();
|
|
}
|
|
|
|
static ALWAYS_INLINE void StopTimer() {
|
|
/* Set the compare value to the maximum. */
|
|
cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(std::numeric_limits<u64>::max()).Store();
|
|
|
|
/* Disable the physical timer. */
|
|
cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(false).SetIMask(false).Store();
|
|
}
|
|
|
|
static ALWAYS_INLINE s64 GetCount() {
|
|
return cpu::CounterTimerPhysicalCountValueRegisterAccessor().GetCount();
|
|
}
|
|
|
|
static ALWAYS_INLINE void SetCompareValue(s64 value) {
|
|
cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(static_cast<u64>(value)).Store();
|
|
}
|
|
|
|
};
|
|
|
|
}
|