Skip to content

Commit 870b5cb

Browse files
committed
x86: pass through cpuid leaves 15h and 16h
These leaves communicate TSC and CPU frequencies to the guest, and are used by the guest as a preferred means of calibration. This is especially important in secret-free contexts, where kvm-clock is not available (so guest cannot get TSC frequency from there), and calibration against PIT is unreliable. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent 44ebe1c commit 870b5cb

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ and this project adheres to
2121
so users need to regenerate snapshots.
2222
- [#4731](https://github.com/firecracker-microvm/firecracker/pull/4731): Added
2323
support for modifying the host TAP device name during snapshot restore.
24+
- [#5186](https://github.com/firecracker-microvm/firecracker/pull/5186): Pass
25+
through CPUID leaves 15h and 16h on Intel CPUs (Crystal clock, processor, and
26+
and bus frequencies).
2427

2528
### Changed
2629

src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::cpu_config::x86_64::cpuid::normalize::{
55
CheckedAssignError, get_range, set_bit, set_range,
66
};
77
use crate::cpu_config::x86_64::cpuid::{
8-
BRAND_STRING_LENGTH, CpuidKey, CpuidRegisters, CpuidTrait, MissingBrandStringLeaves,
8+
BRAND_STRING_LENGTH, CpuidKey, CpuidRegisters, CpuidTrait, MissingBrandStringLeaves, cpuid,
99
host_brand_string,
1010
};
1111

@@ -71,10 +71,53 @@ impl super::IntelCpuid {
7171
self.update_performance_monitoring_entry()?;
7272
self.update_extended_topology_v2_entry();
7373
self.update_brand_string_entry()?;
74+
self.update_frequency_information();
7475

7576
Ok(())
7677
}
7778

79+
/// Passes through the host value of cpuid leaves 15h and 16h if they
80+
/// are not already configured via cpu template.
81+
fn update_frequency_information(&mut self) {
82+
let Some(leaf_15h) = self.get_mut(&CpuidKey::leaf(0x15)) else {
83+
return;
84+
};
85+
86+
if leaf_15h.result == CpuidRegisters::default() {
87+
let host_leaf_15 = cpuid(0x15);
88+
89+
// CPUID.15H:EAX[31:0]
90+
// Ratio of TSC frequency to Core Crystal Clock frequency, denominator
91+
leaf_15h.result.eax = host_leaf_15.eax;
92+
// CPUID.15H:EBX[31:0]
93+
// Ratio of TSC frequency to Core Crystal Clock frequency, numerator
94+
leaf_15h.result.ebx = host_leaf_15.ebx;
95+
// CPUID.15H:ECX[31:0]
96+
// Core Crystal Clock frequency, in units of Hz
97+
leaf_15h.result.ecx = host_leaf_15.ecx;
98+
// edx is reserved
99+
}
100+
101+
let Some(leaf_16h) = self.get_mut(&CpuidKey::leaf(0x16)) else {
102+
return;
103+
};
104+
105+
if leaf_16h.result == CpuidRegisters::default() {
106+
let host_leaf_16 = cpuid(0x16);
107+
108+
// CPUID.16H:EAX[15:0]
109+
// Processor Base Frequency (in MHz)
110+
leaf_16h.result.eax = host_leaf_16.eax;
111+
// CPUID.16H:EBX[15:0]
112+
// Processor Maximum Frequency (in MHz)
113+
leaf_16h.result.ebx = host_leaf_16.ebx;
114+
// CPUID.16H:ECX[15:0]
115+
// Bus/Reference frequency (in MHz)
116+
leaf_16h.result.ecx = host_leaf_16.ecx;
117+
// edx is reserved
118+
}
119+
}
120+
78121
/// Update deterministic cache entry
79122
#[allow(clippy::unwrap_in_result)]
80123
fn update_deterministic_cache_entry(

0 commit comments

Comments
 (0)