| // Copyright Microsoft and CHERIoT Contributors. | |
| // SPDX-License-Identifier: MIT | |
| #pragma once | |
| #include "plic.h" | |
| #include "thread.h" | |
| #include <platform-timer.hh> | |
| #include <stdint.h> | |
| #include <tick_macros.h> | |
| #include <utils.hh> | |
| namespace | |
| { | |
| /** | |
| * Concept for the interface to setting the system timer. | |
| */ | |
| template<typename T> | |
| concept IsTimer = requires(uint32_t cycles) | |
| { | |
| {T::init()}; | |
| {T::setnext(cycles)}; | |
| }; | |
| static_assert( | |
| IsTimer<TimerCore>, | |
| "Platform's timer implementation does not meet the required interface"); | |
| class Timer final : private TimerCore | |
| { | |
| public: | |
| static void interrupt_setup() | |
| { | |
| static_assert(TIMERCYCLES_PER_TICK <= UINT32_MAX, | |
| "Cycles per tick can't be represented in 32 bits. " | |
| "Double check your platform config"); | |
| init(); | |
| setnext(TIMERCYCLES_PER_TICK); | |
| } | |
| static void do_interrupt() | |
| { | |
| ++Thread::ticksSinceBoot; | |
| expiretimers(); | |
| setnext(TIMERCYCLES_PER_TICK); | |
| } | |
| private: | |
| static void expiretimers() | |
| { | |
| if (Thread::waitingList == nullptr) | |
| { | |
| return; | |
| } | |
| for (Thread *iter = Thread::waitingList;;) | |
| { | |
| if (iter->expiryTime <= Thread::ticksSinceBoot) | |
| { | |
| Thread *iterNext = iter->timerNext; | |
| iter->ready(Thread::WakeReason::Timer); | |
| iter = iterNext; | |
| if (Thread::waitingList == nullptr || | |
| iter == Thread::waitingList) | |
| { | |
| break; | |
| } | |
| } | |
| else | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| }; | |
| } // namespace |