9#include "pedigree/kernel/LockGuard.h"
10#include "pedigree/kernel/machine/IrqManager.h"
11#include "pedigree/kernel/machine/Machine.h"
12#include "pedigree/kernel/process/Event.h"
13#include "pedigree/kernel/process/Thread.h"
14#include "pedigree/kernel/processor/Processor.h"
15#include "pedigree/kernel/utilities/String.h"
17#include "DeviceTree.h"
18#include "GenericTimer.h"
21constexpr uint64_t NanosecondsPerSecond = 1000000000ULL;
23bool leapYear(
size_t year) {
24 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
27uint8_t daysInMonth(
size_t year, uint8_t month) {
28 static constexpr uint8_t days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
29 return month == 2 && leapYear(year) ? 29 : days[month - 1];
32uint64_t addDuration(uint64_t deadline,
size_t count, uint64_t multiplier) {
33 if (count > (Time::Infinity - deadline) / multiplier) {
34 return Time::Infinity;
36 return deadline + count * multiplier;
53 m_ElapsedSinceSync(0),
69VirtTimer::~VirtTimer() {
73uint64_t VirtTimer::counter() {
74 return VirtGenericTimer::count();
77uint64_t VirtTimer::ticksToNanoseconds(uint64_t ticks)
const {
81 return (ticks / m_Frequency) * NanosecondsPerSecond +
82 (ticks % m_Frequency) * NanosecondsPerSecond / m_Frequency;
85bool VirtTimer::initialise1() {
89 m_Frequency = VirtGenericTimer::frequency();
93 m_IntervalTicks =
static_cast<uint32_t
>(m_Frequency / 1000);
94 if (!m_IntervalTicks) {
97 m_BootCount = m_LastCount = counter();
100 VirtGenericTimer::physicalControl(0);
105bool VirtTimer::initialise3() {
109 IrqManager& manager = *Machine::instance().getIrqManager();
116 m_LastCount = counter();
118 m_Initialised =
true;
122void VirtTimer::uninitialise() {
131 m_Initialised =
false;
145 if (number != m_IrqId) {
146 return HardStageDisposition::NotHandled;
148 VirtGenericTimer::physicalControl(0);
150 return HardStageDisposition::Deferred;
157 const uint64_t now = counter();
158 const uint64_t delta = ticksToNanoseconds(now - m_LastCount);
160 processElapsed(delta);
164 VirtGenericTimer::physicalControl(0);
169 VirtGenericTimer::setPhysicalTimer(m_IntervalTicks);
177 return ticksToNanoseconds(counter() - m_BootCount);
185 return m_RtcBaseSeconds + ticksToNanoseconds(counter() - m_RtcBaseCount) / NanosecondsPerSecond;
189 return ticksToNanoseconds(counter() - m_RtcBaseCount) % NanosecondsPerSecond;
192void VirtTimer::updateCivilTime(uint64_t seconds) {
193 uint64_t days = seconds / 86400;
194 uint64_t remainder = seconds % 86400;
195 m_DayOfWeek =
static_cast<uint8_t
>((days + 4) % 7);
197 while (days >= (leapYear(m_Year) ? 366U : 365U)) {
198 days -= leapYear(m_Year) ? 366U : 365U;
202 while (days >= daysInMonth(m_Year, m_Month)) {
203 days -= daysInMonth(m_Year, m_Month);
206 m_Day =
static_cast<uint8_t
>(days + 1);
207 m_Hour =
static_cast<uint8_t
>(remainder / 3600);
209 m_Minute =
static_cast<uint8_t
>(remainder / 60);
210 m_Second =
static_cast<uint8_t
>(remainder % 60);
217 const uintptr_t rtc = VirtDeviceTree::rtcBase();
218 const uint64_t count = counter();
219 m_RtcBaseSeconds = rtc ? *
reinterpret_cast<volatile uint32_t*
>(rtc) : 0;
220 m_RtcBaseCount = count;
221 updateCivilTime(m_RtcBaseSeconds);
253 return m_Handlers.registerHandler(handler);
256bool VirtTimer::unregisterHandler(
TimerHandler* handler) {
263 deadline = addDuration(deadline, seconds, Time::Multiplier::Second);
264 deadline = addDuration(deadline, microseconds, Time::Multiplier::Microsecond);
276 if (alarm->event != event) {
279 size_t remaining = 0;
282 remaining = delta / Time::Multiplier::Second + (delta % Time::Multiplier::Second != 0);
291void VirtTimer::processElapsed(uint64_t nanoseconds) {
292 m_ElapsedSinceSync += nanoseconds;
293 if (m_ElapsedSinceSync >= NanosecondsPerSecond) {
295 m_ElapsedSinceSync %= NanosecondsPerSecond;
301 bool dispatched =
false;
304 if (alarm->deadline <= now) {
305 alarm->thread->sendEvent(alarm->event);
318 Machine::instance().getIrqManager()->
tick();
::Iterator< T, node_t > Iterator
static ProcessorInformation & information()
bool acquire(bool recurse=false, bool safe=true)
irq_id_t registerIsaSplitIrq(IrqManager &manager, uint8_t irq, const IrqPolicy &policy)
bool initialiseSplitIrq()
bool dispatch(uint64_t delta, TimerHandler *onlyHandler=nullptr)
bool unregisterHandler(TimerHandler *handler)
void removeAlarm(Event *event) override
size_t getYear() override
void threadedIrq(size_t work) override
uint8_t getDayOfWeek() override
void addAlarm(Event *event, size_t seconds, size_t microseconds=0) override
HardStageDisposition hardIrq(irq_id_t number, InterruptState &state, size_t &work) override
Time::Timestamp getUnixTimestamp() override
void synchronise(bool tohw=false) override
Synchronises the timer with the hardware. Useful for updating the fields returned by get*,...
uint64_t getTickCountNano() override
uint64_t getTickCount() override
bool quiesceIrqSources() override
uint8_t getHour() override
uint8_t getMinute() override
uint8_t getSecond() override
void rearmIrqSources(size_t work) override
uint64_t getNanosecond() override
uint8_t getDayOfMonth() override
uint64_t getTickCountNanoFast() override
uint8_t getMonth() override