rust-kernel
Rustbelt: a hobby x86_64 kernel written in Rust
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | //! A microsecond clock for the network stack.
//!
//! The PIT ticks only ~18.2 times a second (55 ms), far too coarse to time
//! a ping (QEMU answers in well under a millisecond) or to run TCP's
//! retransmit timers. Every x86-64 CPU has a *time stamp counter* (TSC): a
//! 64-bit counter that goes up at a fixed rate, read with `rdtsc`. We don't
//! know that rate, so we measure it once against the PIT (apic.rs does this
//! while it calibrates the APIC timer, over 2 PIT ticks) and from then on
//! `now_us` is just `rdtsc / rate`.
//!
//! Before calibration (or if it never happens, e.g. in some tests) we fall
//! back to counting PIT ticks.
//!
//! Stage 19: the clock counts nanoseconds now (`now_ns`), and the numbers
//! behind it are shared with user space through the vDSO's vvar page (see
//! vdso.rs), so programs can read the time without a system call.
use ;
/// One PIT tick in microseconds (1 / 18.2065 Hz).
pub const PIT_TICK_US: u64 = 54_925;
static TSC_PER_MS: AtomicU64 = new;
static TSC_START: AtomicU64 = new;
/// Stage 19: nanoseconds per TSC tick, as a fixed-point number with 32
/// bits after the point (so 2^32 means "1 ns per tick"). Multiplying and
/// shifting is much cheaper than dividing, and the vDSO (vdso/vdso.c) does
/// the very same arithmetic in user space -- that's why the formula lives
/// in one place, `tsc_to_ns`, and both sides use it. 0 = not calibrated.
static TSC_MULT: AtomicU64 = new;
/// Called with a TSC reading at a PIT tick edge (`start`) and the number of
/// ticks it took to reach `end`.
/// TSC ticks since `TSC_START` -> nanoseconds. Must match `read_clock` in
/// vdso/vdso.c exactly, or the two clocks would disagree.
/// Nanoseconds since boot (CLOCK_MONOTONIC).
/// Microseconds since boot.
/// What the vDSO needs to compute the time by itself: (TSC at time 0,
/// ns-per-tick multiplier (0 = not calibrated), Unix time at boot in ns).
/// The PIT tick by which `us` microseconds from now will surely have
/// passed. For sleeping/timeouts, which may run late but never early: we
/// may be anywhere inside the current ~55 ms tick, so one extra tick.
// ---------------------------------------------------------------------------
// Wall-clock time (CLOCK_REALTIME)
// ---------------------------------------------------------------------------
/// Unix time (nanoseconds since 1970-01-01 UTC) at boot (now_ns = 0),
/// read from the CMOS clock on first use. 0 = not read yet.
static BOOT_REALTIME_NS: AtomicU64 = new;
/// Read a CMOS register (the PC's battery-backed real-time clock).
/// The RTC's date and time as Unix seconds. QEMU's RTC runs on UTC.
/// Days since 1970-01-01 for a date (Howard Hinnant's algorithm).
/// Nanoseconds since 1970-01-01 UTC (clock_gettime(CLOCK_REALTIME)).
/// Microseconds since 1970-01-01 UTC.
|