|
3 | 3 |
|
4 | 4 | use std::collections::HashMap;
|
5 | 5 |
|
| 6 | +use vmm::arch::x86_64::msr::MsrRange; |
| 7 | +use vmm::arch_gen::x86::msr_index::*; |
6 | 8 | 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}; |
8 | 11 | use vmm::cpu_config::x86_64::custom_cpu_template::{
|
9 | 12 | CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, RegisterModifier,
|
10 | 13 | };
|
| 14 | +use vmm::MSR_RANGE; |
11 | 15 |
|
12 | 16 | use crate::utils::x86_64::{cpuid_leaf_modifier, cpuid_reg_modifier, msr_modifier};
|
13 | 17 |
|
@@ -45,10 +49,72 @@ fn msrs_to_modifier(msrs: &HashMap<u32, u64>) -> Vec<RegisterModifier> {
|
45 | 49 | .iter()
|
46 | 50 | .map(|(index, value)| msr_modifier!(*index, *value))
|
47 | 51 | .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 | + |
48 | 58 | msrs.sort_by_key(|modifier| modifier.addr);
|
49 | 59 | msrs
|
50 | 60 | }
|
51 | 61 |
|
| 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 | + |
52 | 118 | #[cfg(test)]
|
53 | 119 | mod tests {
|
54 | 120 | use std::collections::BTreeMap;
|
@@ -122,25 +188,44 @@ mod tests {
|
122 | 188 | }
|
123 | 189 |
|
124 | 190 | fn build_sample_msrs() -> HashMap<u32, u64> {
|
125 |
| - HashMap::from([ |
| 191 | + let mut map = HashMap::from([ |
| 192 | + // should be sorted in the result. |
126 | 193 | (0x1, 0xffff_ffff_ffff_ffff),
|
127 | 194 | (0x5, 0xffff_ffff_0000_0000),
|
128 | 195 | (0x3, 0x0000_0000_ffff_ffff),
|
129 | 196 | (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 |
131 | 208 | }
|
132 | 209 |
|
133 | 210 | fn build_expected_msr_modifiers() -> Vec<RegisterModifier> {
|
134 |
| - vec![ |
| 211 | + let mut v = vec![ |
135 | 212 | msr_modifier!(0x1, 0xffff_ffff_ffff_ffff),
|
136 | 213 | msr_modifier!(0x2, 0x0000_0000_0000_0000),
|
137 | 214 | msr_modifier!(0x3, 0x0000_0000_ffff_ffff),
|
138 | 215 | 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 |
140 | 225 | }
|
141 | 226 |
|
142 | 227 | #[test]
|
143 |
| - fn test_cpuid_to_modifier() { |
| 228 | + fn test_config_to_template() { |
144 | 229 | let cpu_config = CpuConfiguration {
|
145 | 230 | cpuid: build_sample_cpuid(),
|
146 | 231 | msrs: build_sample_msrs(),
|
|
0 commit comments