Skip to content

Commit 48ff6e0

Browse files
committed
refactor(cpu-template-helper): Exclude meaningless MSRs for x86_64
The previous commit made `dump_cpu_config()` not exclude MSRs that can be dumped but are not meaningful in CPU template lifecycle. Instead, excludes those MSRs on the CPU template helper tool's side. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent 08a5ca4 commit 48ff6e0

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

src/cpu-template-helper/src/template/dump/x86_64.rs

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33

44
use std::collections::HashMap;
55

6+
use vmm::arch::x86_64::msr::MsrRange;
7+
use vmm::arch_gen::x86::msr_index::*;
68
use vmm::cpu_config::templates::{CpuConfiguration, CustomCpuTemplate, RegisterValueFilter};
7-
use vmm::cpu_config::x86_64::cpuid::Cpuid;
9+
use vmm::cpu_config::x86_64::cpuid::common::get_vendor_id_from_host;
10+
use vmm::cpu_config::x86_64::cpuid::{Cpuid, VENDOR_ID_AMD};
811
use vmm::cpu_config::x86_64::custom_cpu_template::{
912
CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, RegisterModifier,
1013
};
14+
use vmm::MSR_RANGE;
1115

1216
use crate::utils::x86_64::{cpuid_leaf_modifier, cpuid_reg_modifier, msr_modifier};
1317

@@ -45,10 +49,72 @@ fn msrs_to_modifier(msrs: &HashMap<u32, u64>) -> Vec<RegisterModifier> {
4549
.iter()
4650
.map(|(index, value)| msr_modifier!(*index, *value))
4751
.collect();
52+
53+
msrs.retain(|modifier| !should_exclude_msr(modifier.addr));
54+
if &get_vendor_id_from_host().unwrap() == VENDOR_ID_AMD {
55+
msrs.retain(|modifier| !should_exclude_msr_amd(modifier.addr));
56+
}
57+
4858
msrs.sort_by_key(|modifier| modifier.addr);
4959
msrs
5060
}
5161

62+
// List of MSR indices excluded from the CPU configuration dump.
63+
//
64+
// MSRs that vary depending on the elapsed time (e.g., time stamp counter) are not useful, because
65+
// CPU configuration dump is used to check diff between CPU models and detect changes caused by
66+
// Firecracker/KVM/BIOS changes.
67+
//
68+
// Fireracker diables some features (e.g., PMU) and doesn't support some features (e.g., Hyper-V),
69+
// MSRs related to such features are not useful as CPU configuration dump. Excluding such MSRs
70+
// reduces maintenance cost when KVM makes change their default values.
71+
const MSR_EXCLUSION_LIST: [MsrRange; 9] = [
72+
// - MSR_IA32_TSC (0x10): vary depending on the elapsed time.
73+
MSR_RANGE!(MSR_IA32_TSC),
74+
// Firecracker doesn't support MCE.
75+
// - MSR_IA32_MCG_STATUS (0x17a)
76+
// - MSR_IA32_MCG_EXT_CTL (0x4d0)
77+
MSR_RANGE!(MSR_IA32_MCG_STATUS),
78+
MSR_RANGE!(MSR_IA32_MCG_EXT_CTL),
79+
// - MSR_IA32_PERF_CAPABILITIES (0x345) available if CPUID.01h:ECX[15] = 1 but disabled in the
80+
// CPUID normalization process.
81+
MSR_RANGE!(MSR_IA32_PERF_CAPABILITIES),
82+
// Firecracker doesn't support PEBS (Precise Event-Based Sampling) that is part of Intel's PMU.
83+
// - MSR_IA32_PEBS_ENABLE (0x3F1)
84+
// - MSR_PEBS_DATA_CFG (0x3F2)
85+
// - MSR_IA32_DS_AREA (0x600)
86+
MSR_RANGE!(MSR_IA32_PEBS_ENABLE, 2),
87+
MSR_RANGE!(MSR_IA32_DS_AREA),
88+
// Firecracker doesn't support AMD PMU.
89+
// - MSR_K7_EVNTSELn (0xC0010000..=0xC0010003)
90+
// - MSR_K7_PERFCTRn (0xC0010004..=0xC0010007)
91+
// - MSR_F15H_PERF_CTLn & MSR_F15H_PERF_CTRn (0xC0010200..=0xC001020B)
92+
MSR_RANGE!(MSR_K7_EVNTSEL0, 4),
93+
MSR_RANGE!(MSR_K7_PERFCTR0, 4),
94+
MSR_RANGE!(MSR_F15H_PERF_CTL0, 12),
95+
];
96+
97+
fn should_exclude_msr(index: u32) -> bool {
98+
MSR_EXCLUSION_LIST.iter().any(|range| range.contains(index))
99+
}
100+
101+
// List of MSR indices excluded from the CPU configuration dump on AMD
102+
const MSR_EXCLUSION_LIST_AMD: [MsrRange; 1] = [
103+
// MSR_IA32_ARCH_CAPABILITIES has been emulated by KVM since kernel 5.7.
104+
// https://github.com/torvalds/linux/commit/93c380e7b528882396ca463971012222bad7d82e
105+
// https://lore.kernel.org/all/[email protected]/
106+
// As this MSR is not available on AMD processors, Firecracker disables it explicitly by
107+
// setting 0 to CPUID.(EAX=07H,ECX=0):EDX[bit 29], and this MSR should be removed from the
108+
// dump on AMD.
109+
MSR_RANGE!(MSR_IA32_ARCH_CAPABILITIES),
110+
];
111+
112+
fn should_exclude_msr_amd(index: u32) -> bool {
113+
MSR_EXCLUSION_LIST_AMD
114+
.iter()
115+
.any(|range| range.contains(index))
116+
}
117+
52118
#[cfg(test)]
53119
mod tests {
54120
use std::collections::BTreeMap;
@@ -122,25 +188,44 @@ mod tests {
122188
}
123189

124190
fn build_sample_msrs() -> HashMap<u32, u64> {
125-
HashMap::from([
191+
let mut map = HashMap::from([
192+
// should be sorted in the result.
126193
(0x1, 0xffff_ffff_ffff_ffff),
127194
(0x5, 0xffff_ffff_0000_0000),
128195
(0x3, 0x0000_0000_ffff_ffff),
129196
(0x2, 0x0000_0000_0000_0000),
130-
])
197+
]);
198+
// should be excluded from the result.
199+
MSR_EXCLUSION_LIST
200+
.iter()
201+
.chain(MSR_EXCLUSION_LIST_AMD.iter())
202+
.for_each(|range| {
203+
(range.base..(range.base + range.nmsrs)).for_each(|id| {
204+
map.insert(id, 0);
205+
})
206+
});
207+
map
131208
}
132209

133210
fn build_expected_msr_modifiers() -> Vec<RegisterModifier> {
134-
vec![
211+
let mut v = vec![
135212
msr_modifier!(0x1, 0xffff_ffff_ffff_ffff),
136213
msr_modifier!(0x2, 0x0000_0000_0000_0000),
137214
msr_modifier!(0x3, 0x0000_0000_ffff_ffff),
138215
msr_modifier!(0x5, 0xffff_ffff_0000_0000),
139-
]
216+
];
217+
if &get_vendor_id_from_host().unwrap() != VENDOR_ID_AMD {
218+
MSR_EXCLUSION_LIST_AMD.iter().for_each(|range| {
219+
(range.base..(range.base + range.nmsrs)).for_each(|id| {
220+
v.push(msr_modifier!(id, 0));
221+
})
222+
});
223+
}
224+
v
140225
}
141226

142227
#[test]
143-
fn test_cpuid_to_modifier() {
228+
fn test_config_to_template() {
144229
let cpu_config = CpuConfiguration {
145230
cpuid: build_sample_cpuid(),
146231
msrs: build_sample_msrs(),

src/vmm/src/arch/x86_64/msr.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ pub enum MsrError {
2929

3030
/// MSR range
3131
#[derive(Debug)]
32-
struct MsrRange {
32+
pub struct MsrRange {
3333
/// Base MSR address
34-
base: u32,
34+
pub base: u32,
3535
/// Number of MSRs
36-
nmsrs: u32,
36+
pub nmsrs: u32,
3737
}
3838

3939
impl MsrRange {
4040
/// Returns whether `msr` is contained in this MSR range.
41-
fn contains(&self, msr: u32) -> bool {
41+
pub fn contains(&self, msr: u32) -> bool {
4242
self.base <= msr && msr < self.base + self.nmsrs
4343
}
4444
}
@@ -127,7 +127,8 @@ bitflags! {
127127
}
128128
}
129129

130-
// Macro for generating a MsrRange.
130+
/// Macro for generating a MsrRange.
131+
#[macro_export]
131132
macro_rules! MSR_RANGE {
132133
($base:expr, $nmsrs:expr) => {
133134
MsrRange {

0 commit comments

Comments
 (0)