/* * ApicTimer.hpp * Local APIC timer for periodic tick interrupts and timekeeping * Copyright (c) 2025 Daniel Hammer */ #pragma once #include namespace Timekeeping { // Initialize the APIC timer: calibrate against PIT, start periodic interrupts void ApicTimerInitialize(); // Initialize the scheduler timer on an AP using the BSP calibration. void ApicTimerInitializeAP(); // Idle APs are woken for runnable work by the reschedule IPI, so their // periodic scheduler timer can remain masked until a process is dispatched. void ApicTimerEnterApIdle(); void ApicTimerLeaveApIdle(); // Reinitialize the APIC timer after S3 resume using the previously // calibrated tick rate. Skips PIT calibration and IRQ registration // (both survive in RAM). Only reprograms the timer hardware registers. void ApicTimerReinitialize(); // Get the monotonic tick count (increments on each timer interrupt) uint64_t GetTicks(); // Get elapsed milliseconds since timer initialization uint64_t GetMilliseconds(); // Enable scheduler tick (called after scheduler is initialized) void EnableSchedulerTick(); // Run bounded process-context bottom halves from an idle CPU. void ServiceDeferredWork(); // Enter one idle wait cycle for the current CPU. Uses HLT and relies on // the boot-time periodic LAPIC timer to wake -- one-shot wake doesn't // survive deep C-states on some laptop CPUs. void IdleOnce(bool hasMwait, volatile uint64_t* monitorAddr = nullptr); // Busy-wait sleep for the given number of milliseconds void Sleep(uint64_t ms); // Spin for at least `ms` milliseconds without descheduling. Usable from // boot code, before the scheduler runs, and with interrupts disabled // (falls back to timed I/O port writes when the tick is not advancing). void BusyWaitMs(uint64_t ms); // Spin for at least `us` microseconds. Port-0x80 timed, so it errs long. void BusyWaitUs(uint64_t us); };