From 0cb5eab9332cf87b5463d06c186900b9e7b4304c Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Thu, 27 Feb 2020 01:59:23 +0000 Subject: [PATCH] thermosphere: generic timer rewrite --- .../src/cpu/hvisor_cpu_sysreg_general.hpp | 9 +- thermosphere/src/hvisor_generic_timer.cpp | 61 ++++++++++ thermosphere/src/hvisor_generic_timer.hpp | 103 +++++++++++++++++ thermosphere/src/timer.c | 46 -------- thermosphere/src/timer.h | 108 ------------------ 5 files changed, 172 insertions(+), 155 deletions(-) create mode 100644 thermosphere/src/hvisor_generic_timer.cpp create mode 100644 thermosphere/src/hvisor_generic_timer.hpp delete mode 100644 thermosphere/src/timer.c delete mode 100644 thermosphere/src/timer.h diff --git a/thermosphere/src/cpu/hvisor_cpu_sysreg_general.hpp b/thermosphere/src/cpu/hvisor_cpu_sysreg_general.hpp index 6c1c42ee8..021b79912 100644 --- a/thermosphere/src/cpu/hvisor_cpu_sysreg_general.hpp +++ b/thermosphere/src/cpu/hvisor_cpu_sysreg_general.hpp @@ -438,4 +438,11 @@ namespace ams::hvisor::cpu { PSR_SP_ELX = BITL(0), }; -} + // cnt*_ctl flags + enum CntCtlFlags { + CNTCTL_ISTATUS = BITL(2), + CNTCTL_IMASK = BITL(1), + CNTCTL_ENABLE = BITL(0), + }; + + } diff --git a/thermosphere/src/hvisor_generic_timer.cpp b/thermosphere/src/hvisor_generic_timer.cpp new file mode 100644 index 000000000..4893ebe27 --- /dev/null +++ b/thermosphere/src/hvisor_generic_timer.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019-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 . + */ + +#include "hvisor_generic_timer.hpp" +#include "hvisor_irq_manager.hpp" +#include "hvisor_core_context.hpp" + +#include "cpu/hvisor_cpu_interrupt_mask_guard.hpp" +#include "cpu/hvisor_cpu_instructions.hpp" + +#include + +namespace ams::hvisor { + + void GenericTimer::Initialize() + { + Configure(false, false); + if (currentCoreCtx->IsBootCore()) { + m_timerFreq = THERMOSPHERE_GET_SYSREG(cntfrq_el0); + } + + IrqManager::GetInstance().Register(*this, irqId, true); + } + + std::optional GenericTimer::InterruptTopHalfHandler(u32 irqId, u32) + { + if (irqId != GenericTimer::irqId) { + return std::nullopt; + } + + // Mask the timer interrupt until reprogrammed + Configure(false, false); + + return false; + } + + void GenericTimer::WaitTicks(s64 ticks) + { + IrqManager::EnterInterruptibleHypervisorCode(); + auto flags = cpu::UnmaskIrq(); + SetTimeoutTicks(ticks); + do { + cpu::wfi(); + } while (!GetInterruptStatus()); + cpu::RestoreInterruptFlags(flags); + } + +} diff --git a/thermosphere/src/hvisor_generic_timer.hpp b/thermosphere/src/hvisor_generic_timer.hpp new file mode 100644 index 000000000..32727a991 --- /dev/null +++ b/thermosphere/src/hvisor_generic_timer.hpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019-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 . + */ + +#pragma once +#include "defines.hpp" + +#include "hvisor_i_interrupt_task.hpp" +#include "cpu/hvisor_cpu_sysreg_general.hpp" + +#include "preprocessor.h" +#include "platform/interrupt_config.h" + +#include + +namespace ams::hvisor { + + class GenericTimer final : public IInterruptTask { + SINGLETON(GenericTimer); + private: + static constexpr u32 irqId = GIC_IRQID_NS_PHYS_HYP_TIMER; + + private: + static void Configure(bool enabled, bool interruptMasked) + { + u64 ebit = enabled ? cpu::CNTCTL_ENABLE : 0; + u64 mbit = interruptMasked ? cpu::CNTCTL_IMASK: 0; + THERMOSPHERE_SET_SYSREG(cnthp_ctl_el2, mbit | ebit); + } + + static bool GetInterruptStatus() + { + return (THERMOSPHERE_GET_SYSREG(cnthp_ctl_el2) & cpu::CNTCTL_ISTATUS) != 0; + } + + private: + u64 m_timerFreq = 0; + + private: + constexpr GenericTimer() = default; + + public: + static s64 GetSystemTick() + { + return static_cast(THERMOSPHERE_GET_SYSREG(cntpct_el0)); + } + + static void SetTimeoutTicks(s64 ticks) + { + THERMOSPHERE_SET_SYSREG(cnthp_cval_el2, GetSystemTick() + ticks); + Configure(true, false); + } + + static void WaitTicks(s64 ticks); + + public: + void Initialize(); + std::optional InterruptTopHalfHandler(u32 irqId, u32) final; + + constexpr u64 GetTimerFrequency() const { return m_timerFreq; } + + template> + auto GetSystemTime() const + { + auto tick = GetSystemTick(); + return (tick * SecondRatio::den) / (m_timerFreq * SecondRatio::num); + } + + std::chrono::nanoseconds GetSystemTimeNs() const + { + return std::chrono::nanoseconds{GetSystemTime()}; + } + + template + void SetTimeout(Duration d) const + { + using SecondRatio = typename Duration::period; + auto v = (d.count() * m_timerFreq * SecondRatio::num) / SecondRatio::den; + SetTimeoutTicks(v); + } + + template + void Wait(Duration d) const + { + using SecondRatio = typename Duration::period; + auto v = (d.count() * m_timerFreq * SecondRatio::num) / SecondRatio::den; + WaitTicks(v); + } + }; + +} diff --git a/thermosphere/src/timer.c b/thermosphere/src/timer.c deleted file mode 100644 index 9d3a50926..000000000 --- a/thermosphere/src/timer.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019 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 . - */ - -#include "timer.h" -#include "irq.h" -#include "exceptions.h" - -u64 g_timerFreq = 0; - -void timerInit(void) -{ - timerConfigure(false, false); - if (currentCoreCtx->isBootCore) { - g_timerFreq = GET_SYSREG(cntfrq_el0); - } -} - -void timerInterruptHandler(void) -{ - // Mask the timer interrupt until reprogrammed - timerConfigure(false, false); -} - -void timerWaitUsecs(u64 us) -{ - exceptionEnterInterruptibleHypervisorCode(); - u64 mask = unmaskIrq(); - timerSetTimeoutUs(us); - do { - __wfi(); - } while (!timerGetInterruptStatus()); - restoreInterruptFlags(mask); -} diff --git a/thermosphere/src/timer.h b/thermosphere/src/timer.h deleted file mode 100644 index 6af8fdac1..000000000 --- a/thermosphere/src/timer.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2019 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 . - */ - -#pragma once - -#include "utils.h" -#include "sysreg.h" -#include "platform/interrupt_config.h" - -#define SECTONSECS 1000000000ull -#define SECTOUSECS 1000000ull -#define SECTOMSECS 1000ull - -// All generic timers possibly defined in the Arm architecture: -// (suffix, time source suffix, level, irqid) -#define NS_PHYS_TIMER (p, p, 0, GIC_IRQID_NS_PHYS_TIMER) -#define NS_VIRT_TIMER (v, v, 0, GIC_IRQID_NS_VIRT_TIMER) -#define NS_PHYS_HYP_TIMER (hp, p, 2, GIC_IRQID_NS_PHYS_HYP_TIMER) -#define NS_VIRT_HYP_TIMER (hv, v, 2, GIC_IRQID_NS_VIRT_HYP_TIMER) -#define SEC_PHYS_TIMER (ps, p, 1, GIC_IRQID_SEC_PHYS_TIMER) -#define SEC_PHYS_HYP_TIMER (hps, p, 2, GIC_IRQID_SEC_PHYS_HYP_TIMER) -#define SEC_VIRT_HYP_TIMER (hvs, v, 2, GIC_IRQID_SEC_VIRT_HYP_TIMER) - -#define TIMER_IRQID_FIELDS(ign, ign2, ign3, id) id -#define TIMER_COUNTER_REG_FIELDS(ign, ts, ign2, ign3) cnt##ts##ct_el0 -#define TIMER_CTL_REG_FIELDS(t, ign, el, ign2) cnt##t##_ctl_el##el -#define TIMER_CVAL_REG_FIELDS(t, ign, el, ign2) cnt##t##_cval_el##el -#define TIMER_TVAL_REG_FIELDS(t, ign, el, ign2) cnt##t##_tval_el##el - -#define TIMER_IRQID(name) EVAL(TIMER_IRQID_FIELDS name) -#define TIMER_COUNTER_REG(name) EVAL(TIMER_COUNTER_REG_FIELDS name) -#define TIMER_CTL_REG(name) EVAL(TIMER_CTL_REG_FIELDS name) -#define TIMER_CVAL_REG(name) EVAL(TIMER_CVAL_REG_FIELDS name) -#define TIMER_TVAL_REG(name) EVAL(TIMER_TVAL_REG_FIELDS name) - -#define TIMER_CTL_ISTATUS BITL(2) -#define TIMER_CTL_IMASK BITL(1) -#define TIMER_CTL_ENABLE BITL(0) - -#define CURRENT_TIMER NS_PHYS_HYP_TIMER - -extern u64 g_timerFreq; - -void timerInit(void); -void timerInterruptHandler(void); - -static inline u64 timerGetSystemTick(void) -{ - return GET_SYSREG(TIMER_COUNTER_REG(CURRENT_TIMER)); -} - -static inline bool timerGetInterruptStatus(void) -{ - return (GET_SYSREG(TIMER_CTL_REG(CURRENT_TIMER)) & TIMER_CTL_ISTATUS) != 0; -} - -static inline u64 timerGetSystemTimeNs(void) -{ - return timerGetSystemTick() * SECTONSECS / g_timerFreq; -} - -static inline u64 timerGetSystemTimeMs(void) -{ - return timerGetSystemTick() * SECTOMSECS / g_timerFreq; -} - -static inline void timerConfigure(bool enabled, bool interruptMasked) -{ - u64 ebit = enabled ? TIMER_CTL_ENABLE : 0; - u64 mbit = interruptMasked ? TIMER_CTL_IMASK : 0; - SET_SYSREG(TIMER_CTL_REG(CURRENT_TIMER), mbit | ebit); -} - -static inline void timerSetTimeoutTicks(u64 ticks) -{ - SET_SYSREG(TIMER_CVAL_REG(CURRENT_TIMER), timerGetSystemTick() + ticks); - timerConfigure(true, false); -} - -static inline void timerSetTimeoutNs(u64 ns) -{ - timerSetTimeoutTicks(ns * g_timerFreq / SECTONSECS); -} - -static inline void timerSetTimeoutMs(u64 ms) -{ - timerSetTimeoutTicks(ms * g_timerFreq / SECTOMSECS); -} - -static inline void timerSetTimeoutUs(u64 us) -{ - timerSetTimeoutTicks(us * g_timerFreq / SECTOUSECS); -} - -void timerWaitUsecs(u64 us);