The Pedigree Project 0.1
Rtc.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "Rtc.h"
21#if ACPI
22#include "Acpi.h"
23#endif
24#include "pedigree/kernel/BootstrapInfo.h"
25#include "pedigree/kernel/LockGuard.h"
26#include "pedigree/kernel/Log.h"
27#include "pedigree/kernel/TargetInfo.h"
28#include "pedigree/kernel/compiler.h"
29#include "pedigree/kernel/core/SlamAllocator.h"
30#include "pedigree/kernel/machine/IrqManager.h"
31#include "pedigree/kernel/machine/Machine.h"
32#include "pedigree/kernel/machine/SchedulerTimer.h"
33#include "pedigree/kernel/machine/Serial.h"
34#include "pedigree/kernel/machine/TimerHandler.h"
35#include "pedigree/kernel/panic.h"
36#include "pedigree/kernel/process/PerProcessorScheduler.h"
37#include "pedigree/kernel/process/Process.h"
38#include "pedigree/kernel/process/Scheduler.h"
39#include "pedigree/kernel/process/TerminationDeferral.h"
40#include "pedigree/kernel/process/Thread.h"
41#include "pedigree/kernel/processor/Processor.h"
42#include "pedigree/kernel/processor/ProcessorInformation.h"
43#include "pedigree/kernel/time/Time.h"
44#include "pedigree/kernel/utilities/Iterator.h"
45#include "pedigree/kernel/utilities/StaticString.h"
46#include "pedigree/kernel/utilities/String.h"
47#include "pedigree/kernel/utilities/StringView.h"
48#include "pedigree/kernel/utilities/Vector.h"
49#include "pedigree/kernel/utilities/assert.h"
50#include "pedigree/kernel/utilities/utility.h"
51
52#include "RtcCalendar.h"
53#include "RtcTimeAccounting.h"
54
55class Event;
56extern BootstrapStruct_t* g_pBootstrapInfo;
57
58// RTC frequency to set at startup - tradeoff between precision of timers
59// against constant RTC noise.
61#ifdef BOCHS
62#define INITIAL_RTC_HZ 64
63#else
64#define INITIAL_RTC_HZ 512
65#endif
66
67namespace {
68constexpr uint8_t RtcPeriodicInterruptEnable = 1U << 6;
69constexpr uint8_t RtcAlarmInterruptEnable = 1U << 5;
70constexpr uint8_t RtcUpdateEndedInterruptEnable = 1U << 4;
71constexpr uint8_t RtcInterruptEnableMask =
72 RtcPeriodicInterruptEnable | RtcAlarmInterruptEnable | RtcUpdateEndedInterruptEnable;
73constexpr uint8_t RtcUpdateInhibit = 1U << 7;
74constexpr uint8_t RtcInterruptRequested = 1U << 7;
75constexpr uint8_t RtcPeriodicFlag = 1U << 6;
76// MC146818A UIP can remain asserted for up to 2.228 ms. This margin also
77// accommodates compatible devices, emulators, and the uncalibrated TSC used
78// during initialise1().
79constexpr Time::Timestamp RtcUpdateTimeout = 25 * Time::Multiplier::Millisecond;
80constexpr size_t RtcUpdateMaximumPolls = 1000000;
81constexpr size_t RtcCalibrationMaximumPolls = 100000000;
82
83ALWAYS_INLINE inline uint64_t readOrderedTsc() {
84 uint32_t edx = 0;
85 uint32_t eax = 0;
86 asm volatile("lfence\nrdtsc" : "=d"(edx), "=a"(eax) : : "memory");
87 return (static_cast<uint64_t>(edx) << 32U) | eax;
88}
89
90#if ACPI
91bool calibrateTscFromPmTimer(uint64_t& tsc0, uint64_t& tsc1, uint64_t& elapsedNanoseconds) {
92 uint16_t port = 0;
93 uint32_t mask = 0;
94 if (!Acpi::instance().getPmTimerPort(port, mask)) {
95 return false;
96 }
97 IoPort timer("ACPI PM timer calibration");
98 if (!timer.allocate(port, 4)) {
99 WARNING("RTC: ACPI PM timer port unavailable; using RTC calibration");
100 return false;
101 }
102
103 constexpr uint64_t Frequency = 3579545;
104 constexpr uint64_t SampleTicks = Frequency / 10;
105 size_t polls = 0;
106 for (size_t attempt = 0; attempt < 3; ++attempt) {
107 const uint64_t startBefore = readOrderedTsc();
108 uint32_t previous = timer.read32() & mask;
109 const uint64_t startAfter = readOrderedTsc();
110 uint64_t elapsedTicks = 0;
111 while (elapsedTicks < SampleTicks) {
112 const uint32_t current = timer.read32() & mask;
113 // Both counter widths may wrap between reads.
114 elapsedTicks += (current - previous) & mask;
115 previous = current;
116 if (++polls >= RtcCalibrationMaximumPolls) {
117 WARNING("RTC: ACPI PM timer calibration timed out; using RTC calibration");
118 return false;
119 }
121 }
122 const uint64_t endBefore = readOrderedTsc();
123 const uint32_t current = timer.read32() & mask;
124 const uint64_t endAfter = readOrderedTsc();
125 elapsedTicks += (current - previous) & mask;
126
127 if (startAfter < startBefore || endBefore <= startAfter || endAfter < endBefore) {
128 continue;
129 }
130 const uint64_t startSpan = startAfter - startBefore;
131 const uint64_t endSpan = endAfter - endBefore;
132 tsc0 = startBefore + startSpan / 2;
133 tsc1 = endBefore + endSpan / 2;
134 // Bound endpoint uncertainty, including host deschedules, to 0.1%.
135 if (startSpan + endSpan > (tsc1 - tsc0) / 1000) {
136 continue;
137 }
138 elapsedNanoseconds = elapsedTicks * Time::Multiplier::Second / Frequency;
139 return true;
140 }
141 WARNING("RTC: ACPI PM timer calibration endpoints were delayed; using RTC calibration");
142 return false;
143}
144#endif
145} // namespace
146
148 {4, 0x0e, {250000000ULL, 250000000ULL}}, {8, 0x0d, {125000000ULL, 125000000ULL}},
149 {16, 0x0c, {62500000ULL, 62500000ULL}}, {32, 0x0b, {31250000ULL, 31250000ULL}},
150 {64, 0x0a, {15625000ULL, 15625000ULL}}, {128, 0x09, {7812500ULL, 7812500ULL}},
151 {256, 0x08, {3906250ULL, 3906250ULL}}, {512, 0x07, {1953125ULL, 1953125ULL}},
152 {1024, 0x06, {976562ULL, 976563ULL}}, {2048, 0x05, {488281ULL, 488281ULL}},
153 {4096, 0x04, {244140ULL, 244141ULL}}, {8192, 0x03, {122070ULL, 122070ULL}},
154};
155
156static uint64_t addAlarmDuration(uint64_t deadline, size_t count, uint64_t multiplier) {
157 if (count > ((Time::Infinity - deadline) / multiplier)) {
158 return Time::Infinity;
159 }
160 return deadline + (count * multiplier);
161}
162
164
165bool Rtc::CmosTransactionGuard::waitableContext() {
166 return Processor::information().getCurrentThread() && Processor::getInterrupts() &&
168}
169
170Rtc::CmosTransactionGuard::CmosTransactionGuard(Mutex& lock)
171 : m_Waitable(waitableContext()),
172 m_TerminationDeferral(m_Waitable),
173 m_Lock(lock),
174 m_Owned(false) {
176 panic("RTC CMOS transaction attempted from a hard IRQ");
177 }
178
179 m_Owned = m_Waitable ? m_Lock.acquireForCompletion() : m_Lock.tryAcquire();
180 if (!m_Owned) {
181 panic("RTC CMOS transaction contended in an atomic context");
182 }
183}
184
185Rtc::CmosTransactionGuard::~CmosTransactionGuard() {
186 if (m_Owned) {
187 m_Lock.release();
188 }
189}
190
191static void* currentAlarmDispatchOwner() {
193}
194
195void Rtc::addAlarm(Event* pEvent, size_t alarmSecs, size_t alarmUsecs) {
196 Alarm* pAlarm = nullptr;
197 m_Lock.acquire();
198 pAlarm = m_AlarmQueue.takeReusable();
199 m_Lock.release();
200
201 if (!pAlarm) {
202 pAlarm = new Alarm;
203 }
204
205 const uint64_t now = getTickCountNano();
207
208 // Figure out when to trigger the alarm.
209 uint64_t target = addAlarmDuration(now, alarmSecs, Time::Multiplier::Second);
210 target = addAlarmDuration(target, alarmUsecs, Time::Multiplier::Microsecond);
211 pAlarm->prepare(pEvent, target, Processor::information().getCurrentThread());
212 m_AlarmQueue.add(pAlarm);
213 if (m_DeadlineMode) {
214 publishNextDeadlineLocked();
215 }
216}
217
218void Rtc::drainRemoteAlarmDispatch(Event* pEvent, void* owner) {
219 Thread* current = Processor::information().getCurrentThread();
220 const bool canYield = current && Processor::getInterrupts();
221 TerminationDeferral terminationDeferral(canYield);
222 uintptr_t previousDebugAddress = 0;
223 Thread::DebugState previousDebugState = Thread::None;
224 bool debuggingDrain = false;
225
226 while (true) {
227 m_Lock.acquire();
228 const bool dispatching = m_AlarmQueue.hasRemoteInFlight(pEvent, owner);
229 m_Lock.release();
230
231 if (!dispatching) {
232 break;
233 }
234
235 if (canYield) {
236 if (!debuggingDrain) {
237 previousDebugState = current->getDebugState(previousDebugAddress);
238 current->setDebugState(Thread::CallbackDrain, reinterpret_cast<uintptr_t>(pEvent));
239 debuggingDrain = true;
240 }
242 } else {
244 }
245 }
246
247 if (debuggingDrain) {
248 current->setDebugState(previousDebugState, previousDebugAddress);
249 }
250}
251
252void Rtc::removeAlarm(Event* pEvent) {
253 void* owner = currentAlarmDispatchOwner();
254 bool remoteInFlight = false;
255 bool selfDeferred = false;
256
257 m_Lock.acquire();
258 Alarm* reclaim = m_AlarmQueue.removeAllQueued(pEvent, owner, remoteInFlight, selfDeferred);
259 m_AlarmQueue.recycleList(reclaim);
260 if (m_DeadlineMode) {
261 publishNextDeadlineLocked();
262 }
263 m_Lock.release();
264
265 (void)selfDeferred;
266 if (remoteInFlight) {
267 drainRemoteAlarmDispatch(pEvent, owner);
268 }
269}
270
271size_t Rtc::removeAlarm(class Event* pEvent, bool bRetZero) {
272 void* owner = currentAlarmDispatchOwner();
273 const uint64_t currTime = getTickCountNano();
274
275 m_Lock.acquire();
276 RtcAlarmQueue::Removal removal = m_AlarmQueue.removeFirst(pEvent, owner);
277 if (removal.record) {
278 m_AlarmQueue.recycleList(removal.record);
279 }
280 if (m_DeadlineMode) {
281 publishNextDeadlineLocked();
282 }
283 m_Lock.release();
284
285 if (removal.disposition == RtcAlarmQueue::RemovalDisposition::RemoteInFlight) {
286 drainRemoteAlarmDispatch(pEvent, owner);
287 return 0;
288 }
289 if (removal.disposition != RtcAlarmQueue::RemovalDisposition::Removed || bRetZero ||
290 removal.deadline < currTime) {
291 return 0;
292 }
293
294 const uint64_t diff = removal.deadline - currTime;
295 size_t ret = diff / Time::Multiplier::Second;
296 if (diff % Time::Multiplier::Second) {
297 ++ret;
298 }
299 return ret;
300}
301
302bool Rtc::registerHandler(TimerHandler* handler) {
303 return m_HandlerRegistry.registerHandler(handler);
304}
305
306bool Rtc::unregisterHandler(TimerHandler* handler) {
307 const bool removed = m_HandlerRegistry.unregisterHandler(handler);
308 if (removed && m_DeadlineMode) {
310 publishNextDeadlineLocked();
311 }
312 return removed;
313}
314
315bool Rtc::armHandler(TimerHandler* handler, uint64_t absoluteDeadlineNs) {
316 if (!m_DeadlineMode) {
317 return false;
318 }
320 if (!m_HandlerRegistry.armHandler(handler, absoluteDeadlineNs, getTickCountNano())) {
321 return false;
322 }
323 publishNextDeadlineLocked();
324 return true;
325}
326
327void Rtc::publishNextDeadlineLocked() {
328 assert(m_DeadlineScheduler);
329 uint64_t next = m_AlarmQueue.nextDeadline();
330 const uint64_t handlerDeadline = m_HandlerRegistry.nextDeadline();
331 if (handlerDeadline < next) {
332 next = handlerDeadline;
333 }
334 m_DeadlineScheduler->setClockDeadline(next == Time::Infinity ? 0 : next);
335}
336
338 if (!m_DeadlineMode) {
339 return;
340 }
341 m_DeadlinePending = 1;
342 m_DeadlineScheduler->ringIrqWorkDoorbell(m_DeadlineWake, false);
343}
344
345int Rtc::deadlineWorkerEntry(void* context) {
346 return reinterpret_cast<Rtc*>(context)->runDeadlineWorker();
347}
348
349int Rtc::runDeadlineWorker() {
350 TerminationDeferral workerLifetime;
351 while (!m_StopDeadlineWorker.value()) {
352 if (m_DeadlinePending.compareAndSwap(1, 0)) {
353 const uint64_t now = getTickCountNano();
356 {
358 publishNextDeadlineLocked();
359 }
361 continue;
362 }
363 auto guard = m_DeadlineWaiters.acquire();
364 if (!m_DeadlinePending.value() && !m_StopDeadlineWorker.value()) {
365 const WaitQueue::WakeReason reason =
366 guard.wait(WaitQueue::Channel(), Thread::CondWait, reinterpret_cast<uintptr_t>(this));
367 (void)reason;
368 }
369 }
370 return 0;
371}
372size_t Rtc::getYear() {
373 return m_Year;
374}
375uint8_t Rtc::getMonth() {
376 return m_Month;
377}
379 return m_DayOfMonth;
380}
382 static size_t monthnumbers[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
383
384 // Calculate day of week
385 uint8_t dayOfWeek = m_DayOfMonth % 7;
386 dayOfWeek += monthnumbers[m_Month - 1];
387 dayOfWeek += ((m_Year % 100) + ((m_Year % 100) / 4)) % 7;
388 dayOfWeek -= ((m_Year / 100) % 4 - 3) * 2;
389 if (m_Month < 3)
390 dayOfWeek--;
391 dayOfWeek %= 7;
392
393 return dayOfWeek;
394}
395uint8_t Rtc::getHour() {
396 return m_Hour;
397}
398uint8_t Rtc::getMinute() {
399 return m_Minute;
400}
401uint8_t Rtc::getSecond() {
402 return m_Second;
403}
405 return m_Nanosecond;
406}
407Time::Timestamp Rtc::getUnixTimestamp() {
408 // initialise3 anchors realtime before enabling deadline mode. Direct
409 // filesystem users must see that running clock even when no timer is due.
410 return m_DeadlineMode ? Time::getTimeNanoseconds() / Time::Multiplier::Second
412}
414 return getTickCountNano() / Time::Multiplier::Millisecond;
415}
417 // Migration between the TSC sample and the per-CPU anchor would combine
418 // unrelated clock domains. Keep only that bounded snapshot non-preemptible;
419 // conversion and global publication do not depend on the current CPU.
420 const bool interruptsWereEnabled = Processor::getInterrupts();
422 uint64_t anchorTsc = m_Tsc0;
423 uint64_t anchorNanoseconds = 0;
424 Processor::information().getTscClockAnchor(anchorTsc, anchorNanoseconds);
425 const uint64_t tsc = readOrderedTsc();
426 Processor::setInterrupts(interruptsWereEnabled);
427
428 uint64_t candidate = PcTscClock::fromAnchor(tsc, anchorTsc, anchorNanoseconds, m_TscCalibration);
429 const uint64_t coarseFloor = m_TickCount.value();
430 if (candidate < coarseFloor) {
431 candidate = coarseFloor;
432 }
433
434 return m_MonotonicTicks.publish(candidate);
435}
436
438 return Rtc::sampleCpuTime().timestamp;
439}
440
442 // The RTC cursor advances in its worker, after the measured thread has
443 // switched out. Accounting needs a clock which advances on this thread.
444 // Callers already mask IRQs and reset their baselines on CPU migration,
445 // so the immutable local anchor needs no global monotonic publication.
446 uint64_t anchorTsc = m_Tsc0;
447 uint64_t anchorNanoseconds = 0;
448 const ProcessorInformation& processor = Processor::information();
449 processor.getTscClockAnchor(anchorTsc, anchorNanoseconds);
450 const uint64_t timestamp =
451 PcTscClock::fromAnchor(readOrderedTsc(), anchorTsc, anchorNanoseconds, m_TscCalibration);
452 return {timestamp, Processor::index()};
453}
454
455bool Rtc::initialise1(uint8_t centuryIndex) {
456 NOTICE("Rtc::initialise1");
457
458 // Allocate the I/O port range"CMOS"
459 if (m_IoPort.allocate(0x70, 2) == false)
460 return false;
461
462 // No IRQ yet.
463 m_IrqId = 0;
464
465 // Initialise handlers.
467
468 if (!RtcCalendar::validCenturyIndex(centuryIndex)) {
469 ERROR("RTC: unsupported FADT century index " << Hex << centuryIndex);
470 return false;
471 }
472 m_CenturyIndex = centuryIndex;
473 if (centuryIndex) {
474 NOTICE("RTC: FADT century index " << Hex << centuryIndex);
475 } else {
476 NOTICE("RTC: no century register; interpreting years as 1970-2069");
477 }
478
479 uint8_t statusB = 0;
480 if (!read(0x0B, statusB) ||
481 !write(0x0B, statusB & ~(RtcUpdateInhibit | RtcInterruptEnableMask | 1U))) {
482 return false;
483 }
484
485 // Find the initial rtc rate
486 uint8_t rateBits = 0x06;
487 for (size_t i = 0; i < 12; i++)
488 if (periodicIrqInfo[i].Hz == INITIAL_RTC_HZ) {
490 rateBits = periodicIrqInfo[i].rateBits;
491 break;
492 }
493
494 // Set the Rate for the periodic IRQ
495 // Select the standard 32.768 kHz divider and a running clock, regardless
496 // of the divider/reset and interrupt state left by firmware.
497 uint8_t statusA = 0;
498 uint8_t verifiedB = 0;
499 if (!write(0x0A, 0x20 | rateBits) || !read(0x0A, statusA) || !read(0x0B, verifiedB) ||
500 (statusA & 0x7f) != (0x20 | rateBits) ||
501 verifiedB != (statusB & ~(RtcUpdateInhibit | RtcInterruptEnableMask | 1U))) {
502 ERROR("RTC: control register configuration did not stick");
503 return false;
504 }
505 if (!readHardwareClock()) {
506 ERROR("RTC: initial hardware clock is invalid or unresponsive");
507 return false;
508 }
509 return true;
510}
511
513 NOTICE("Rtc::initialise2");
514
515 uint64_t tsc0 = 0;
516 uint64_t tsc1 = 0;
517 uint64_t elapsedNanoseconds = 0;
518 bool usedPmTimer = false;
519#if ACPI
520 usedPmTimer = calibrateTscFromPmTimer(tsc0, tsc1, elapsedNanoseconds);
521#endif
522 if (!usedPmTimer) {
523 // IRQ8 is still masked. The RTC fallback cannot distinguish coalesced
524 // periods, so prefer the cumulative ACPI counter when it is available.
525 constexpr size_t CalibrationPeriods = 50;
527 size_t calibrationPolls = 0;
528 while (!(read(0x0C) & RtcPeriodicFlag)) {
529 if (++calibrationPolls >= RtcCalibrationMaximumPolls) {
531 ERROR("RTC: timed out waiting for TSC calibration to start");
532 return false;
533 }
535 }
536
537 tsc0 = readOrderedTsc();
538
539 size_t periods = 0;
540 while (periods < CalibrationPeriods) {
541 if (read(0x0C) & RtcPeriodicFlag) {
542 ++periods;
543 }
544 if (++calibrationPolls >= RtcCalibrationMaximumPolls) {
546 ERROR("RTC: timed out collecting periodic TSC calibration samples");
547 return false;
548 }
550 }
551
552 tsc1 = readOrderedTsc();
554
555 for (size_t i = 0; i < CalibrationPeriods; ++i) {
556 elapsedNanoseconds += periodicIrqInfo[m_PeriodicIrqInfoIndex].ns[i & 1];
557 }
558 }
559 if (tsc1 <= tsc0 || !elapsedNanoseconds) {
560 ERROR("RTC: invalid TSC calibration interval");
561 return false;
562 }
563 const uint64_t elapsedCycles = tsc1 - tsc0;
564 m_TscCalibration = PcTscClock::Calibration(elapsedCycles, elapsedNanoseconds);
565 NOTICE("TSC calibration: " << elapsedCycles << " cycles / " << elapsedNanoseconds << " ns ("
566 << (usedPmTimer ? "ACPI PM timer" : "RTC") << ")");
567
568 m_TickCount = 0;
570 m_Tsc0 = tsc1;
571 m_MonotonicTicks.reset();
572 Processor::information().initialiseTscClockAnchor(tsc1, 0);
573#if PEDIGREE_LATENCY_ACCOUNTING
574 const bool interruptsWereEnabled = Processor::getInterrupts();
576 LatencyAccounting::armCpu();
577 Processor::setInterrupts(interruptsWereEnabled);
578#endif
579
580 return true;
581}
582
584 const bool interruptsWereEnabled = Processor::getInterrupts();
586 ProcessorInformation& processor = Processor::information();
587 const uint64_t tsc = readOrderedTsc();
588 uint64_t nanoseconds = m_MonotonicTicks.value();
589 const uint64_t coarseFloor = m_TickCount.value();
590 if (nanoseconds < coarseFloor) {
591 nanoseconds = coarseFloor;
592 }
593 processor.initialiseTscClockAnchor(tsc, nanoseconds);
594 LatencyAccounting::armCpu();
595 Processor::setInterrupts(interruptsWereEnabled);
596}
597
599 size_t selectedIndex = m_PeriodicIrqInfoIndex;
600 bool rateSpecified = false;
601 const char* commandLine = g_pBootstrapInfo->getCommandLine();
602 if (commandLine) {
603 Vector<String> arguments = String(commandLine).tokenise(' ');
604 for (const auto& argument : arguments) {
605 const StringView view = argument.view();
606 constexpr size_t PrefixLength = 9;
607 if (!(view == "--rtc-hz") &&
608 (view.length() < PrefixLength || !(view.substring(0, PrefixLength) == "--rtc-hz=")))
609 continue;
610
611 size_t hz = 0;
612 bool valid = !rateSpecified && view.length() > PrefixLength;
613 for (size_t i = PrefixLength; valid && i < view.length(); ++i) {
614 const char digit = view[i];
615 valid = digit >= '0' && digit <= '9' && hz <= 8192;
616 if (valid)
617 hz = hz * 10 + static_cast<size_t>(digit - '0');
618 }
619 size_t index = 0;
620 while (index < 12 && periodicIrqInfo[index].Hz != hz)
621 ++index;
622 if (!valid || index == 12) {
623 ERROR("RTC: invalid or repeated --rtc-hz option: " << argument);
624 return false;
625 }
626 selectedIndex = index;
627 rateSpecified = true;
628 }
629 }
630
631 // Keep boot TSC calibration identical across runtime-rate experiments.
632 // Periodic interrupts are still disabled and IRQ8 has no handler yet.
633 const uint8_t statusA = 0x20 | periodicIrqInfo[selectedIndex].rateBits;
634 uint8_t verifiedA = 0;
635 if (!write(0x0A, statusA) || !read(0x0A, verifiedA) || (verifiedA & 0x7f) != statusA) {
636 ERROR("RTC: runtime interrupt frequency did not stick");
637 return false;
638 }
639 m_PeriodicIrqInfoIndex = selectedIndex;
640 SchedulerTimer* schedulerTimer = Machine::instance().getSchedulerTimer();
641 if (schedulerTimer && schedulerTimer->supportsOneShot()) {
642 m_DeadlineScheduler = Scheduler::schedulerForCpu(0);
643 if (!m_DeadlineScheduler) {
644 return false;
645 }
646 const uint64_t baseline = getTickCountNano();
647 m_TickCount = baseline;
648 m_ProcessedTickCount = baseline;
649 if (!Time::anchorRealtime(Time::getTimeNanoseconds())) {
650 return false;
651 }
652 m_DeadlineScheduler->registerWorkerWake(m_DeadlineWake, m_DeadlineWaiters);
653 Thread* worker = new Thread(Scheduler::instance().getKernelProcess(), deadlineWorkerEntry, this,
654 nullptr, false, true, true);
655 worker->setName("clock deadline worker");
656 m_DeadlineWorker.adopt(worker);
657 m_DeadlineMode = true;
658 if (!worker->start()) {
659 FATAL("RTC deadline worker could not be started.");
660 }
661 {
663 publishNextDeadlineLocked();
664 }
665 NOTICE("RTC: runtime IRQ8 disabled; CPU 0 LAPIC handles timer deadlines");
666 return true;
667 }
668
669 IrqManager& irqManager = *Machine::instance().getIrqManager();
670 m_IrqId = irqManager.registerIsaIrqHandler(8, this, IrqPolicy::levelThreaded());
671 if (!m_IrqId) {
672 return false;
673 }
674
675 const uint64_t baseline = getTickCountNano();
676 m_TickCount = baseline;
677 m_ProcessedTickCount = baseline;
678 NOTICE("RTC: periodic interrupt frequency " << Dec << periodicIrqInfo[selectedIndex].Hz << " Hz");
680 return true;
681}
682
683void Rtc::synchronise(bool tohw) {
684 const bool success = tohw ? writeHardwareClock() : readHardwareClock();
685
686 if (!success) {
687 if (tohw) {
688 ERROR("RTC: hardware clock write failed (invalid date or timeout)");
689 } else {
690 ERROR("RTC: hardware clock read failed (invalid date or timeout)");
691 }
692 }
693}
695 if (m_DeadlineMode) {
696 m_StopDeadlineWorker = 1;
697 m_DeadlineScheduler->setClockDeadline(0);
698 m_DeadlineScheduler->ringIrqWorkDoorbell(m_DeadlineWake);
699 m_DeadlineWorker.join();
700 m_DeadlineScheduler->unregisterWorkerWake(m_DeadlineWake);
701 advanceCivilClock(getTickCountNano());
702 m_DeadlineMode = 0;
703 }
705 if (m_IrqId && !Machine::instance().getIrqManager()->unregisterHandler(m_IrqId, this)) {
706 panic("RTC teardown could not drain its threaded IRQ callback");
707 }
708 m_IrqId = 0;
709
710 synchronise(true);
711
713
714 Alarm* reclaim = nullptr;
715 Alarm* freeAlarms = nullptr;
716 {
718 reclaim = m_AlarmQueue.detachActive();
719 freeAlarms = m_AlarmQueue.detachFree();
720 }
721 while (reclaim) {
722 Alarm* next = reclaim->next();
723 delete reclaim;
724 reclaim = next;
725 }
726 while (freeAlarms) {
727 Alarm* next = freeAlarms->next();
728 delete freeAlarms;
729 freeAlarms = next;
730 }
731
732 // Free the I/O port range
733 m_IoPort.free();
734}
735
737 : m_IoPort("CMOS"),
738 m_IrqId(0),
740 m_CenturyIndex(0),
741 m_Year(1970),
742 m_Month(1),
743 m_DayOfMonth(1),
744 m_Hour(0),
745 m_Minute(0),
746 m_Second(0),
747 m_Nanosecond(0),
748 m_TickCount(0),
751 m_DeadlineScheduler(nullptr),
752 m_DeadlineWorker(),
753 m_DeadlineWaiters(),
754 m_DeadlineWake(),
755 m_DeadlinePending(0),
756 m_StopDeadlineWorker(0),
757 m_DeadlineMode(false),
758 m_AlarmQueue(),
759 m_Lock(false),
760 m_CmosLock(),
762 m_Tsc0(0),
764
765extern size_t g_FreePages;
766extern size_t g_AllocedPages;
767
768IrqDisposition Rtc::irq(irq_id_t number) {
769 (void)number;
770
771 uint8_t status = 0;
772 {
774 status = readLocked(0x0C);
775 }
776
777 if (!(status & RtcInterruptRequested)) {
778 return IrqDisposition::Handled;
779 }
780 if (!(status & RtcPeriodicFlag)) {
781 return IrqDisposition::Handled;
782 }
783
785 return IrqDisposition::Handled;
786}
787
788void Rtc::processElapsedTime(uint64_t observed) {
789 uint64_t elapsedSeconds = 0;
790 const uint64_t delta = advanceCivilClock(observed, &elapsedSeconds);
791 if (!delta) {
792 return;
793 }
794
795 // Claim one due alarm under the queue lock, then publish it without
796 // carrying that lock into Event or allocator code. A remover which sees
797 // m_bDispatching waits for this ownership handoff to finish before it
798 // returns and permits the Event to be reclaimed.
799 while (true) {
800 m_Lock.acquire();
801 Alarm* claimed = m_AlarmQueue.claimDue(m_ProcessedTickCount, currentAlarmDispatchOwner());
802 m_Lock.release();
803
804 if (!claimed) {
805 break;
806 }
807
808 Thread* target = reinterpret_cast<Thread*>(claimed->target());
809 Event* event = reinterpret_cast<Event*>(claimed->event());
810 target->sendEvent(event);
811
812 m_Lock.acquire();
813 m_AlarmQueue.completeDispatch(claimed);
814 m_Lock.release();
815 }
816
817 if (UNLIKELY(delta >= Time::Multiplier::Millisecond ||
818 m_Nanosecond >= Time::Multiplier::Millisecond)) {
819 // Every millisecond, unblock any interrupts which were halted and halt
820 // any which need to be halted.
821 Machine::instance().getIrqManager()->tick();
822 }
823
824 if (UNLIKELY(elapsedSeconds)) {
825#if MEMORY_LOGGING_ENABLED
826 Serial* pSerial = Machine::instance().getSerial(1);
827 NormalStaticString memoryLogStr;
828 memoryLogStr += "Heap: ";
829 memoryLogStr += (SlamAllocator::instance().heapPageCount() * TargetInfo::getPageSize()) / 1024;
830 memoryLogStr += "K\tPages: ";
831 memoryLogStr += (g_AllocedPages * TargetInfo::getPageSize()) / 1024;
832 memoryLogStr += "K\t Free: ";
833 memoryLogStr += (g_FreePages * TargetInfo::getPageSize()) / 1024;
834 memoryLogStr += "K\n";
835
836 pSerial->write_str(memoryLogStr);
837
838 // Memory snapshot of current processes.
839 for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); ++i) {
840 Scheduler::ProcessLease processLease;
841 if (!Scheduler::instance().acquireProcess(processLease, i)) {
842 continue;
843 }
844 Process* pProcess = processLease.get();
845 LargeStaticString processListStr;
846
847 ssize_t heapK = pProcess->getHeapUsage() / 1024;
848 ssize_t virtK = (pProcess->getVirtualPageCount() * TargetInfo::getPageSize()) / 1024;
849 ssize_t physK = (pProcess->getPhysicalPageCount() * TargetInfo::getPageSize()) / 1024;
850 ssize_t shrK = (pProcess->getSharedPageCount() * TargetInfo::getPageSize()) / 1024;
851
852 processListStr.append("\tProcess #");
853 processListStr.append(pProcess->getId(), 10);
854 processListStr.append(" '");
855 processListStr.append(pProcess->description());
856 processListStr.append("' V=");
857 processListStr.append(virtK, 10);
858 processListStr.append("K P=");
859 processListStr.append(physK, 10);
860 processListStr.append("K S=");
861 processListStr.append(shrK, 10);
862 processListStr.append("K Heap=");
863 processListStr.append(heapK, 10);
864 processListStr.append("K\n");
865 pSerial->write_str(processListStr);
866 }
867#endif
868 }
869
870 // Timer delta is in nanoseconds.
871 if (!m_DeadlineMode) {
873 }
874}
875
876uint64_t Rtc::advanceCivilClock(uint64_t observed, uint64_t* elapsedSeconds) {
877 const uint64_t delta = RtcTimeAccounting::consumeElapsed(observed, m_ProcessedTickCount);
878 if (!delta) {
879 return 0;
880 }
884 const uint64_t seconds = RtcTimeAccounting::advanceCivilTime(civilTime, delta);
885 m_Year = civilTime.year;
886 m_Month = civilTime.month;
887 m_DayOfMonth = civilTime.day;
888 m_Hour = civilTime.hour;
889 m_Minute = civilTime.minute;
890 m_Second = civilTime.second;
891 m_Nanosecond = civilTime.nanosecond;
892 if (elapsedSeconds) {
893 *elapsedSeconds = seconds;
894 }
895 return delta;
896}
897
898void Rtc::setIndexLocked(uint8_t index) {
899 uint8_t idx = m_IoPort.read8(0);
900 m_IoPort.write8((idx & 0x80) | (index & 0x7F), 0);
901}
902
903bool Rtc::waitForUpdateCompletion(uint8_t index) {
904 if (index > 9 && index != m_CenturyIndex) {
905 return true;
906 }
907
908 const Time::Timestamp started = Time::getTicks();
909 size_t polls = 0;
910 while (true) {
911 bool updating = false;
912 {
914 setIndexLocked(0x0A);
915 updating = (m_IoPort.read8(1) & 0x80) != 0;
916 }
917 if (!updating) {
918 return true;
919 }
920 if (++polls >= RtcUpdateMaximumPolls || (Time::getTicks() - started) >= RtcUpdateTimeout) {
921 ERROR(
922 "RTC: timed out waiting for update completion before CMOS "
923 "index "
924 << index);
925 return false;
926 }
928 }
929}
930uint8_t Rtc::readCmos(uint8_t index) {
931 return m_Instance.read(index);
932}
933
934uint8_t Rtc::read(uint8_t index) {
935 uint8_t value = 0xFF;
936 (void)read(index, value);
937 return value;
938}
939
940bool Rtc::read(uint8_t index, uint8_t& value) {
941 if (!waitForUpdateCompletion(index)) {
942 return false;
943 }
944 CmosTransactionGuard guard(m_CmosLock);
945 value = readLocked(index);
946 return true;
947}
948
949uint8_t Rtc::readLocked(uint8_t index) {
950 setIndexLocked(index);
951 return m_IoPort.read8(1);
952}
953
954bool Rtc::write(uint8_t index, uint8_t value) {
955 if (!waitForUpdateCompletion(index)) {
956 return false;
957 }
958
960 writeLocked(index, value);
961 return true;
962}
963
964void Rtc::writeCmos(uint8_t index, uint8_t value) {
965 (void)m_Instance.write(index, value);
966}
967
968bool Rtc::inhibitClockUpdatesLocked(uint8_t& status) {
969 // UIP's quiet window is only guaranteed for 244 us. Do not allow a
970 // scheduler preemption between the final check and freezing the clock.
971 const bool interrupts = Processor::getInterrupts();
973 if (readLocked(0x0A) & 0x80) {
974 Processor::setInterrupts(interrupts);
975 return false;
976 }
977 status = readLocked(0x0B);
978 writeLocked(0x0B, status | RtcUpdateInhibit);
979 const bool inhibited = (readLocked(0x0B) & RtcUpdateInhibit) != 0;
980 Processor::setInterrupts(interrupts);
981 return inhibited;
982}
983
985 if (!waitForUpdateCompletion(0)) {
986 return false;
987 }
989 uint8_t status = 0;
990 if (!inhibitClockUpdatesLocked(status)) {
991 return false;
992 }
994 const bool success =
995 RtcCalendar::read([this](uint8_t index) { return readLocked(index); }, m_CenturyIndex, time);
996 writeLocked(0x0B, status);
997 if (!success) {
998 return false;
999 }
1000 m_Second = time.second;
1001 m_Minute = time.minute;
1002 m_Hour = time.hour;
1003 m_DayOfMonth = time.day;
1004 m_Month = time.month;
1005 m_Year = time.year;
1006 return true;
1007}
1008
1009bool Rtc::writeHardwareClock() {
1011 m_Second, 0};
1012 if (!RtcCalendar::valid(time) || (!m_CenturyIndex && time.year > 2069) ||
1014 return false;
1015 }
1016 CmosTransactionGuard guard(m_CmosLock);
1017 uint8_t status = 0;
1018 if (!inhibitClockUpdatesLocked(status)) {
1019 return false;
1020 }
1021 const bool success = RtcCalendar::write(
1022 [this](uint8_t index) { return readLocked(index); },
1023 [this](uint8_t index, uint8_t value) { writeLocked(index, value); }, m_CenturyIndex, time);
1024 writeLocked(0x0B, status);
1025 return success;
1026}
1027
1028void Rtc::writeLocked(uint8_t index, uint8_t value) {
1029 setIndexLocked(index);
1030 m_IoPort.write8(value, 1);
1031}
1032
1035 const uint8_t status = readLocked(0x0B);
1036 const uint8_t quiescentStatus = static_cast<uint8_t>(status & ~RtcInterruptEnableMask);
1037 writeLocked(0x0B, enabled ? static_cast<uint8_t>(quiescentStatus | RtcPeriodicInterruptEnable)
1038 : quiescentStatus);
1039
1040 // Some RTCs require register C to be cleared after control changes.
1041 (void)readLocked(0x0C);
1042}
Definition Event.h:49
I/O port range.
Definition IoPort.h:33
void free()
Definition IoPort.cc:42
bool allocate(io_port_t ioPort, size_t size)
Definition IoPort.cc:29
virtual void write8(uint8_t value, size_t offset=0)
virtual uint8_t read8(size_t offset=0)
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, const IrqPolicy &policy)=0
virtual void tick()
Definition IrqManager.cc:53
virtual SchedulerTimer * getSchedulerTimer()=0
virtual Serial * getSerial(size_t n)=0
Definition Mutex.h:56
void join()
Definition OwnedThread.h:49
void setClockDeadline(uint64_t deadline)
void registerWorkerWake(SchedulerWorkerWake &worker, WaitQueue &waiters)
void unregisterWorkerWake(SchedulerWorkerWake &worker)
ssize_t getHeapUsage() const
Definition Process.h:902
size_t getId()
Definition Process.h:499
LargeStaticString & description()
Definition Process.h:525
static bool getInterrupts()
static ProcessorInformation & information()
static void pause()
static bool inDeviceHardIrq()
Definition Processor.h:581
static void setInterrupts(bool bEnable)
static size_t index()
static void * dispatchOwnerForContext(Context &context)
Definition Rtc.h:50
virtual uint64_t getTickCount()
Definition Rtc.cc:413
void setIndexLocked(uint8_t index)
Definition Rtc.cc:898
RtcAlarmQueue m_AlarmQueue
Definition Rtc.h:245
static periodicIrqInfo_t periodicIrqInfo[12]
Definition Rtc.h:147
static EXPORTED_PUBLIC uint8_t readCmos(uint8_t index)
Definition Rtc.cc:930
void uninitialise()
Definition Rtc.cc:694
virtual uint8_t getHour()
Definition Rtc.cc:395
Mutex m_CmosLock
Definition Rtc.h:250
size_t m_PeriodicIrqInfoIndex
Definition Rtc.h:190
uint8_t m_Hour
Definition Rtc.h:201
uint8_t m_Second
Definition Rtc.h:205
virtual uint8_t getDayOfMonth()
Definition Rtc.cc:378
void processElapsedTime(uint64_t observed)
Definition Rtc.cc:788
virtual uint8_t getMinute()
Definition Rtc.cc:398
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)
Definition Rtc.cc:195
Time::CpuTimeSample sampleCpuTime() override
Definition Rtc.cc:441
uint64_t m_Tsc0
Definition Rtc.h:256
virtual void removeAlarm(class Event *pEvent)
Definition Rtc.cc:252
uint64_t m_ProcessedTickCount
Definition Rtc.h:213
virtual uint8_t getMonth()
Definition Rtc.cc:375
Time::Timestamp getUnixTimestamp() override
Definition Rtc.cc:407
virtual void synchronise(bool tohw=false)
Definition Rtc.cc:683
virtual size_t getYear()
Definition Rtc.cc:372
bool armHandler(TimerHandler *handler, uint64_t absoluteDeadlineNs) override
Definition Rtc.cc:315
virtual uint64_t getNanosecond()
Definition Rtc.cc:404
virtual uint64_t getTickCountNano()
Definition Rtc.cc:416
virtual uint8_t getSecond()
Definition Rtc.cc:401
bool initialise3()
Definition Rtc.cc:598
bool initialise1(uint8_t centuryIndex) INITIALISATION_ONLY
Definition Rtc.cc:455
virtual uint8_t getDayOfWeek()
Definition Rtc.cc:381
bool waitForUpdateCompletion(uint8_t index)
Definition Rtc.cc:903
uint64_t m_Nanosecond
Definition Rtc.h:207
IrqDisposition irq(irq_id_t number) override
Definition Rtc.cc:768
uint8_t m_DayOfMonth
Definition Rtc.h:199
bool readHardwareClock()
Definition Rtc.cc:984
IoPort m_IoPort
Definition Rtc.h:184
irq_id_t m_IrqId
Definition Rtc.h:187
static Rtc m_Instance
Definition Rtc.h:229
void setPeriodicInterruptEnabled(bool enabled)
Definition Rtc.cc:1033
Rtc() INITIALISATION_ONLY
Definition Rtc.cc:736
uint8_t m_Month
Definition Rtc.h:197
bool initialise2() INITIALISATION_ONLY
Definition Rtc.cc:512
PcTscClock::Calibration m_TscCalibration
Definition Rtc.h:253
PcTscClock::MonotonicPublication m_MonotonicTicks
Definition Rtc.h:259
Spinlock m_Lock
Definition Rtc.h:247
void deadlineInterrupt() override
Definition Rtc.cc:337
Atomic< uint64_t > m_TickCount
Definition Rtc.h:210
void drainRemoteAlarmDispatch(class Event *pEvent, void *owner)
Definition Rtc.cc:218
virtual uint64_t getTickCountNanoFast()
Definition Rtc.cc:437
TimerHandlerRegistry m_HandlerRegistry
Definition Rtc.h:232
bool write(uint8_t index, uint8_t value)
Definition Rtc.cc:954
size_t m_Year
Definition Rtc.h:195
void initialiseProcessorClock() INITIALISATION_ONLY
Definition Rtc.cc:583
uint8_t m_Minute
Definition Rtc.h:203
static Scheduler & instance()
Definition Scheduler.h:96
size_t getNumProcesses()
Definition Scheduler.cc:268
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
Definition Scheduler.cc:275
void yield()
Definition Scheduler.cc:236
void release(size_t n=1)
Definition Semaphore.cc:549
void release()
Definition Spinlock.cc:168
bool acquire(bool recurse=false, bool safe=true)
Definition Spinlock.cc:36
StringView substring(size_t start, size_t end, bool hashed=HASH_STRINGVIEWS_BY_DEFAULT) const
static constexpr size_t getPageSize() noexcept
Definition TargetInfo.h:40
void setDebugState(DebugState state, uintptr_t address)
Definition Thread.h:593
DebugState
Definition Thread.h:177
DebugState getDebugState(uintptr_t &address)
Definition Thread.h:574
bool sendEvent(Event *pEvent)
Definition Thread.cc:1115
bool armHandler(TimerHandler *handler, uint64_t deadline, uint64_t now)
bool dispatchDue(uint64_t now)
bool dispatch(uint64_t delta, TimerHandler *onlyHandler=nullptr)
bool unregisterHandler(TimerHandler *handler)
virtual Time::Timestamp getUnixTimestamp()
Definition Timer.cc:29
A vector / dynamic array.
Definition Vector.h:33
MUST_USE_RESULT WakeReason wait(const Channel &channel=Channel(), size_t debugState=0, uintptr_t debugAddress=0, StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
Definition WaitQueue.cc:104
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
IrqDisposition
Definition IrqHandler.h:31
uint64_t ns[2]
Definition Rtc.h:222