1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/213149158): Remove after uses are added.
6*bb4ee6a4SAndroid Build Coastguard Worker #![allow(dead_code)]
7*bb4ee6a4SAndroid Build Coastguard Worker
8*bb4ee6a4SAndroid Build Coastguard Worker use std::arch::x86_64::CpuidResult;
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker /// Function to retrieve the given CPUID leaf and sub-leaf.
11*bb4ee6a4SAndroid Build Coastguard Worker pub type CpuidCountFn = unsafe fn(u32, u32) -> CpuidResult;
12*bb4ee6a4SAndroid Build Coastguard Worker
13*bb4ee6a4SAndroid Build Coastguard Worker /// Gets the TSC frequency for cpuid leaf 0x15 from the existing leaves 0x15 and 0x16.
14*bb4ee6a4SAndroid Build Coastguard Worker ///
15*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
16*bb4ee6a4SAndroid Build Coastguard Worker /// * `cpuid_count`: function that returns the CPUID information for the given leaf/subleaf
17*bb4ee6a4SAndroid Build Coastguard Worker /// combination. `std::arch::x86_64::__cpuid_count` may be used to provide the CPUID information
18*bb4ee6a4SAndroid Build Coastguard Worker /// from the host.
tsc_frequency_cpuid(cpuid_count: CpuidCountFn) -> Option<hypervisor::CpuIdEntry>19*bb4ee6a4SAndroid Build Coastguard Worker pub fn tsc_frequency_cpuid(cpuid_count: CpuidCountFn) -> Option<hypervisor::CpuIdEntry> {
20*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
21*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
22*bb4ee6a4SAndroid Build Coastguard Worker let result = unsafe { cpuid_count(0, 0) };
23*bb4ee6a4SAndroid Build Coastguard Worker if result.eax < 0x15 {
24*bb4ee6a4SAndroid Build Coastguard Worker return None;
25*bb4ee6a4SAndroid Build Coastguard Worker }
26*bb4ee6a4SAndroid Build Coastguard Worker
27*bb4ee6a4SAndroid Build Coastguard Worker let mut tsc_freq = hypervisor::CpuIdEntry {
28*bb4ee6a4SAndroid Build Coastguard Worker // 0x15 is the TSC frequency leaf.
29*bb4ee6a4SAndroid Build Coastguard Worker function: 0x15,
30*bb4ee6a4SAndroid Build Coastguard Worker index: 0,
31*bb4ee6a4SAndroid Build Coastguard Worker flags: 0,
32*bb4ee6a4SAndroid Build Coastguard Worker cpuid: CpuidResult {
33*bb4ee6a4SAndroid Build Coastguard Worker eax: 0,
34*bb4ee6a4SAndroid Build Coastguard Worker ebx: 0,
35*bb4ee6a4SAndroid Build Coastguard Worker ecx: 0,
36*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
37*bb4ee6a4SAndroid Build Coastguard Worker },
38*bb4ee6a4SAndroid Build Coastguard Worker };
39*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
40*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
41*bb4ee6a4SAndroid Build Coastguard Worker tsc_freq.cpuid = unsafe { cpuid_count(tsc_freq.function, tsc_freq.index) };
42*bb4ee6a4SAndroid Build Coastguard Worker
43*bb4ee6a4SAndroid Build Coastguard Worker if tsc_freq.cpuid.ecx != 0 {
44*bb4ee6a4SAndroid Build Coastguard Worker Some(tsc_freq)
45*bb4ee6a4SAndroid Build Coastguard Worker } else {
46*bb4ee6a4SAndroid Build Coastguard Worker // The core crystal frequency is missing. Old kernels (<5.3) don't try to derive it from the
47*bb4ee6a4SAndroid Build Coastguard Worker // CPU base clock speed. Here, we essentially implement
48*bb4ee6a4SAndroid Build Coastguard Worker // https://lore.kernel.org/patchwork/patch/1064690/ so that old kernels can calibrate TSC.
49*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
50*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the host supports `cpuid` instruction.
51*bb4ee6a4SAndroid Build Coastguard Worker let cpu_clock = unsafe {
52*bb4ee6a4SAndroid Build Coastguard Worker // 0x16 is the base clock frequency leaf.
53*bb4ee6a4SAndroid Build Coastguard Worker cpuid_count(0x16, 0)
54*bb4ee6a4SAndroid Build Coastguard Worker };
55*bb4ee6a4SAndroid Build Coastguard Worker if cpu_clock.eax > 0 {
56*bb4ee6a4SAndroid Build Coastguard Worker // Here, we assume the CPU base clock is the core crystal clock, as is done in the patch
57*bb4ee6a4SAndroid Build Coastguard Worker // that exists in 5.3+ kernels. We further assume that the core crystal clock is exactly
58*bb4ee6a4SAndroid Build Coastguard Worker // the TSC frequency. As such, we expose the base clock scaled by the _inverse_ of the
59*bb4ee6a4SAndroid Build Coastguard Worker // "tsc freq" / "core crystal clock freq" ratio. That way when the kernel extracts
60*bb4ee6a4SAndroid Build Coastguard Worker // the frequency & multiplies by the ratio, it obtains the TSC frequency.
61*bb4ee6a4SAndroid Build Coastguard Worker //
62*bb4ee6a4SAndroid Build Coastguard Worker // base_mhz = cpu_clock.eax
63*bb4ee6a4SAndroid Build Coastguard Worker // tsc_to_base_ratio = tsc_freq.eax / tsc_freq.ebx
64*bb4ee6a4SAndroid Build Coastguard Worker // crystal_hz = base_mhz * tsc_base_to_clock_ratio * 10^6
65*bb4ee6a4SAndroid Build Coastguard Worker tsc_freq.cpuid.ecx = (cpu_clock.eax as f64 * tsc_freq.cpuid.eax as f64 * 1_000_000_f64
66*bb4ee6a4SAndroid Build Coastguard Worker / tsc_freq.cpuid.ebx as f64)
67*bb4ee6a4SAndroid Build Coastguard Worker .round() as u32;
68*bb4ee6a4SAndroid Build Coastguard Worker Some(tsc_freq)
69*bb4ee6a4SAndroid Build Coastguard Worker } else {
70*bb4ee6a4SAndroid Build Coastguard Worker None
71*bb4ee6a4SAndroid Build Coastguard Worker }
72*bb4ee6a4SAndroid Build Coastguard Worker }
73*bb4ee6a4SAndroid Build Coastguard Worker }
74*bb4ee6a4SAndroid Build Coastguard Worker
75*bb4ee6a4SAndroid Build Coastguard Worker /// Given the tsc frequency in Hz and the bus frequency in Hz, return a fake version of
76*bb4ee6a4SAndroid Build Coastguard Worker /// cpuid leaf 0x15.
fake_tsc_frequency_cpuid(tsc_hz: u64, bus_hz: u32) -> CpuidResult77*bb4ee6a4SAndroid Build Coastguard Worker pub fn fake_tsc_frequency_cpuid(tsc_hz: u64, bus_hz: u32) -> CpuidResult {
78*bb4ee6a4SAndroid Build Coastguard Worker // We use 1000 for the crystal clock ratio denominator so we can preserve precision in case
79*bb4ee6a4SAndroid Build Coastguard Worker // tsc_hz is not neatly divisible by bus_hz
80*bb4ee6a4SAndroid Build Coastguard Worker let crystal_clock_ratio_denominator: u32 = 1000;
81*bb4ee6a4SAndroid Build Coastguard Worker let crystal_clock_ratio_numerator: u32 =
82*bb4ee6a4SAndroid Build Coastguard Worker (tsc_hz * crystal_clock_ratio_denominator as u64 / bus_hz as u64) as u32;
83*bb4ee6a4SAndroid Build Coastguard Worker
84*bb4ee6a4SAndroid Build Coastguard Worker CpuidResult {
85*bb4ee6a4SAndroid Build Coastguard Worker eax: crystal_clock_ratio_denominator,
86*bb4ee6a4SAndroid Build Coastguard Worker ebx: crystal_clock_ratio_numerator,
87*bb4ee6a4SAndroid Build Coastguard Worker ecx: bus_hz,
88*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker
92*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the Bus frequency in Hz, based on reading Intel-specific cpuids, or None
93*bb4ee6a4SAndroid Build Coastguard Worker /// if the frequency can't be determined from cpuids.
bus_freq_hz(cpuid_count: CpuidCountFn) -> Option<u32>94*bb4ee6a4SAndroid Build Coastguard Worker pub fn bus_freq_hz(cpuid_count: CpuidCountFn) -> Option<u32> {
95*bb4ee6a4SAndroid Build Coastguard Worker tsc_frequency_cpuid(cpuid_count).map(|cpuid| cpuid.cpuid.ecx)
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the TSC frequency in Hz, based on reading Intel-specific cpuids, or None
99*bb4ee6a4SAndroid Build Coastguard Worker /// if the frequency can't be determined from cpuids.
tsc_freq_hz(cpuid_count: CpuidCountFn) -> Option<u32>100*bb4ee6a4SAndroid Build Coastguard Worker pub fn tsc_freq_hz(cpuid_count: CpuidCountFn) -> Option<u32> {
101*bb4ee6a4SAndroid Build Coastguard Worker tsc_frequency_cpuid(cpuid_count).map(|cpuid| {
102*bb4ee6a4SAndroid Build Coastguard Worker (cpuid.cpuid.ecx as u64 * cpuid.cpuid.ebx as u64 / cpuid.cpuid.eax as u64) as u32
103*bb4ee6a4SAndroid Build Coastguard Worker })
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker
106*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
107*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
108*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
109*bb4ee6a4SAndroid Build Coastguard Worker
110*bb4ee6a4SAndroid Build Coastguard Worker #[test]
111*bb4ee6a4SAndroid Build Coastguard Worker // It seems that most Intel CPUs don't have any TSC frequency information in CPUID.15H.ECX. The
112*bb4ee6a4SAndroid Build Coastguard Worker // linux kernel only treats the TSC frequency as a "known" frequency if it comes from
113*bb4ee6a4SAndroid Build Coastguard Worker // CPUID.15H.ECX, and we want our TSC frequency to be "known" to prevent clock watchdogs from
114*bb4ee6a4SAndroid Build Coastguard Worker // invalidating the TSC clocksource. So we derive CPUID.15H.ECX from the values in CPUID.16H.
115*bb4ee6a4SAndroid Build Coastguard Worker // This test verifies that that derivation is working correctly.
test_leaf15_derivation()116*bb4ee6a4SAndroid Build Coastguard Worker fn test_leaf15_derivation() {
117*bb4ee6a4SAndroid Build Coastguard Worker const CRYSTAL_CLOCK_RATIO: u32 = 88;
118*bb4ee6a4SAndroid Build Coastguard Worker const TSC_FREQUENCY_HZ: u32 = 2100000000u32;
119*bb4ee6a4SAndroid Build Coastguard Worker
120*bb4ee6a4SAndroid Build Coastguard Worker let fake_cpuid = |function: u32, index: u32| {
121*bb4ee6a4SAndroid Build Coastguard Worker match (function, index) {
122*bb4ee6a4SAndroid Build Coastguard Worker (0, 0) => {
123*bb4ee6a4SAndroid Build Coastguard Worker CpuidResult {
124*bb4ee6a4SAndroid Build Coastguard Worker eax: 0x16, // highest available leaf is 0x16
125*bb4ee6a4SAndroid Build Coastguard Worker ebx: 0,
126*bb4ee6a4SAndroid Build Coastguard Worker ecx: 0,
127*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
128*bb4ee6a4SAndroid Build Coastguard Worker }
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker (0x15, 0) => {
131*bb4ee6a4SAndroid Build Coastguard Worker CpuidResult {
132*bb4ee6a4SAndroid Build Coastguard Worker eax: 2, // eax usually contains 2, and ebx/eax is the crystal clock ratio
133*bb4ee6a4SAndroid Build Coastguard Worker ebx: CRYSTAL_CLOCK_RATIO * 2,
134*bb4ee6a4SAndroid Build Coastguard Worker ecx: 0,
135*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker (0x16, 0) => {
139*bb4ee6a4SAndroid Build Coastguard Worker CpuidResult {
140*bb4ee6a4SAndroid Build Coastguard Worker eax: TSC_FREQUENCY_HZ / 1_000_000_u32, // MHz frequency
141*bb4ee6a4SAndroid Build Coastguard Worker ebx: 0,
142*bb4ee6a4SAndroid Build Coastguard Worker ecx: 0,
143*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
144*bb4ee6a4SAndroid Build Coastguard Worker }
145*bb4ee6a4SAndroid Build Coastguard Worker }
146*bb4ee6a4SAndroid Build Coastguard Worker _ => CpuidResult {
147*bb4ee6a4SAndroid Build Coastguard Worker eax: 0,
148*bb4ee6a4SAndroid Build Coastguard Worker ebx: 0,
149*bb4ee6a4SAndroid Build Coastguard Worker ecx: 0,
150*bb4ee6a4SAndroid Build Coastguard Worker edx: 0,
151*bb4ee6a4SAndroid Build Coastguard Worker },
152*bb4ee6a4SAndroid Build Coastguard Worker }
153*bb4ee6a4SAndroid Build Coastguard Worker };
154*bb4ee6a4SAndroid Build Coastguard Worker
155*bb4ee6a4SAndroid Build Coastguard Worker // We compare the frequencies divided by the CRYSTAL_CLOCK_RATIO because that's the
156*bb4ee6a4SAndroid Build Coastguard Worker // resolution that the tsc frequency is stored at in CPUID.15H.ECX.
157*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
158*bb4ee6a4SAndroid Build Coastguard Worker tsc_freq_hz(fake_cpuid).unwrap() / CRYSTAL_CLOCK_RATIO,
159*bb4ee6a4SAndroid Build Coastguard Worker TSC_FREQUENCY_HZ / CRYSTAL_CLOCK_RATIO
160*bb4ee6a4SAndroid Build Coastguard Worker );
161*bb4ee6a4SAndroid Build Coastguard Worker }
162*bb4ee6a4SAndroid Build Coastguard Worker }
163