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);