Skip to content

Commit 08a5ca4

Browse files
committed
refactor(vmm): Remove dumpable MSR indices from undumpable list
`UNDUMPABLE_MSR_RANGES` had two classes of MSR indices: one for really undumpable MSRs due to disablement of some features and the other for MSRs that are dumpable but not reasonable to be included in the CPU template helper tool's fingerprint. The second class is removed from `UNDUMPABLE_MSR_RANGES`, but instead will be excluded on the CPU template helper tool's side in the next commit. Thanks to this separation, the dumped CPU configuration might be usable for other usecases than CPU template helper, although there isn't such a usecase right now. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent a9ad576 commit 08a5ca4

File tree

1 file changed

+82
-146
lines changed

1 file changed

+82
-146
lines changed

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

Lines changed: 82 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ use crate::arch_gen::x86::hyperv::*;
1010
use crate::arch_gen::x86::hyperv_tlfs::*;
1111
use crate::arch_gen::x86::msr_index::*;
1212
use crate::arch_gen::x86::perf_event::*;
13-
use crate::cpu_config::x86_64::cpuid::common::{get_vendor_id_from_host, GetCpuidError};
14-
use crate::cpu_config::x86_64::cpuid::VENDOR_ID_AMD;
13+
use crate::cpu_config::x86_64::cpuid::common::GetCpuidError;
1514

1615
#[derive(Debug, PartialEq, Eq, thiserror::Error, displaydoc::Display)]
1716
/// MSR related errors.
@@ -271,159 +270,109 @@ pub fn get_msrs_to_save(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
271270
Ok(msr_index_list)
272271
}
273272

274-
// List of MSRs that should not be included in the dump of CPU configuration.
273+
// List of MSRs that cannot be dumped.
275274
//
276-
// KVM_GET_MSR_INDEX_LIST returns some MSR indices that KVM_GET_MSRS fails to get (e.g., PMU,
277-
// VMX, MCE and Hyper-V related MSRs).
278-
//
279-
// Firecracker disables PMU by default in CPUID normalization for leaf 0xa. Due to this, PMU-
280-
// related MSRs cannot be gotten via KVM_GET_MSRS. The dependency on CPUID leaf 0xa can be found
281-
// in the following link.
275+
// KVM_GET_MSR_INDEX_LIST returns some MSR indices that KVM_GET_MSRS fails to get depending on
276+
// configuration. For example, Firecracker disables PMU by default in CPUID normalization for CPUID
277+
// leaf 0xA. Due to this, some PMU-related MSRs cannot be retrieved via KVM_GET_MSRS. The dependency
278+
// on CPUID leaf 0xA can be found in the following link.
282279
// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/vmx/pmu_intel.c?h=v5.10.176#n325
283280
//
284-
// We don't test if firecarcker works with nested virtualization environment. To avoid undefined
285-
// behavior, we exclude these VMX-related MSRs. You can see that VMX-related MSRs depend on whether
286-
// nested virtualization is allowed in the following link.
287-
// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/vmx/vmx.c?h=v5.10.176#n1950
288-
//
289-
// In kernel 4.14, IA32_MCG_CTL MSR can be gotten only if IA32_MCG_CAP.CTL_P[8] = 1 for vcpu.
290-
// IA32_MCG_CAP can be set up via KVM_X86_SETUP_MCE, but firecracker does not support this. To
291-
// avoid KVM_GET_MSRS failure on kernel 4.14, MCE-related MSRs are removed from the list.
292-
// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/x86.c?h=v4.14.311#n2553
293-
//
294-
// As firecracker does not work with Hyper-V, it is safe to ignore Hyper-V related MSRs.
295-
//
296-
// IA32_TSC MSR is for time stamp counter and can change as time goes on. KVM_GET_MSRS can get this
297-
// MSR safely, but should not be included in the dumped CPU configuration because it is used to
298-
// check diff between CPU models and detect changes of CPU configuration caused by firecracker/KVM/
299-
// BIOS changes.
300-
//
301-
// The list of MSRs that is potentially returned by KVM_GET_MSR_INDEX_LIST can be found in the
302-
// following link (`msrs_to_save_all` + `num_emulated_msrs`):
281+
// The list of MSR indices returned by KVM_GET_MSR_INDEX_LIST can be found in the following link
282+
// (`msrs_to_save_all` + `num_emulated_msrs`).
303283
// https://elixir.bootlin.com/linux/v5.10.176/source/arch/x86/kvm/x86.c#L1211
304-
static UNDUMPABLE_MSR_RANGES: &[MsrRange] = &[
305-
// MSR_IA32_TSC
306-
MSR_RANGE!(MSR_IA32_TSC),
307-
// MSR_ARCH_PERFMON_PERFCTRn
308-
MSR_RANGE!(MSR_ARCH_PERFMON_PERFCTR0, 18),
309-
// MSR_ARCH_PERFMON_EVENTSELn
310-
MSR_RANGE!(MSR_ARCH_PERFMON_EVENTSEL0, 18),
311-
// MSR_ARCH_PERFMON_FIXED_CTRn
312-
MSR_RANGE!(MSR_ARCH_PERFMON_FIXED_CTR0, 3),
313-
// MSR_CORE_PERF_FIXED_CTR_CTRL
314-
// MSR_CORE_PERF_GLOBAL_STATUS
315-
// MSR_CORE_PERF_GLOBAL_CTRL
316-
// MSR_CORE_PERF_GLOBAL_OVF_CTRL
284+
const UNDUMPABLE_MSR_RANGES: [MsrRange; 17] = [
285+
// - MSR_ARCH_PERFMON_FIXED_CTRn (0x309..=0x30C): CPUID.0Ah:EDX[0:4] > 0
286+
MSR_RANGE!(MSR_ARCH_PERFMON_FIXED_CTR0, 4),
287+
// - MSR_CORE_PERF_FIXED_CTR_CTRL (0x38D): CPUID:0Ah:EAX[7:0] > 1
288+
// - MSR_CORE_PERF_GLOBAL_STATUS (0x38E): CPUID:0Ah:EAX[7:0] > 0 ||
289+
// (CPUID.(EAX=07H,ECX=0):EBX[25] = 1 && CPUID.(EAX=014H,ECX=0):ECX[0] = 1)
290+
// - MSR_CORE_PERF_GLOBAL_CTRL (0x39F): CPUID.0AH: EAX[7:0] > 0
291+
// - MSR_CORE_PERF_GLOBAL_OVF_CTRL (0x390): CPUID.0AH: EAX[7:0] > 0 && CPUID.0AH: EAX[7:0] <= 3
317292
MSR_RANGE!(MSR_CORE_PERF_FIXED_CTR_CTRL, 4),
318-
// MSR_IA32_PEBS_ENABLE
319-
// MSR_PEBS_DATA_CFG
320-
MSR_RANGE!(MSR_IA32_PEBS_ENABLE, 2),
321-
// MSR_IA32_DS_AREA
322-
MSR_RANGE!(MSR_IA32_DS_AREA),
323-
// MSR_IA32_PERF_CAPABILITIES
324-
MSR_RANGE!(MSR_IA32_PERF_CAPABILITIES),
325-
// MSR_K7_EVNTSELn
326-
MSR_RANGE!(MSR_K7_EVNTSEL0, 4),
327-
// MSR_K7_PERFCTRn
328-
MSR_RANGE!(MSR_K7_PERFCTR0, 4),
329-
// MSR_F15H_PERF_CTLn
330-
MSR_RANGE!(MSR_F15H_PERF_CTL0, 12),
331-
// MSR_F15H_PERF_CTRn
332-
MSR_RANGE!(MSR_F15H_PERF_CTR0, 12),
333-
// MSR_IA32_VMX_BASIC
334-
// MSR_IA32_VMX_PINBASED_CTLS
335-
// MSR_IA32_VMX_PROCBASED_CTLS
336-
// MSR_IA32_VMX_EXIT_CTLS
337-
// MSR_IA32_VMX_ENTRY_CTLS
338-
// MSR_IA32_VMX_MISC
339-
// MSR_IA32_VMX_CR0_FIXED0
340-
// MSR_IA32_VMX_CR0_FIXED1
341-
// MSR_IA32_VMX_CR4_FIXED0
342-
// MSR_IA32_VMX_CR4_FIXED1
343-
// MSR_IA32_VMX_VMCS_ENUM
344-
// MSR_IA32_VMX_PROCBASED_CTLS2
345-
// MSR_IA32_VMX_EPT_VPID_CAP
346-
// MSR_IA32_VMX_TRUE_PINBASED_CTLS
347-
// MSR_IA32_VMX_TRUE_PROCBASED_CTLS
348-
// MSR_IA32_VMX_TRUE_EXIT_CTLS
349-
// MSR_IA32_VMX_TRUE_ENTRY_CTLS
350-
// MSR_IA32_VMX_VMFUNC
293+
// - MSR_ARCH_PERFMON_PERFCTRn (0xC1..=0xC8): CPUID.0AH:EAX[15:8] > 0
294+
MSR_RANGE!(MSR_ARCH_PERFMON_PERFCTR0, 8),
295+
// - MSR_ARCH_PERFMON_EVENTSELn (0x186..=0x18D): CPUID.0AH:EAX[15:8] > 0
296+
MSR_RANGE!(MSR_ARCH_PERFMON_EVENTSEL0, 8),
297+
// On kernel 4.14, IA32_MCG_CTL (0x17B) can be retrieved only if IA32_MCG_CAP.CTL_P[8] = 1 for
298+
// vCPU. IA32_MCG_CAP can be set up via KVM_X86_SETUP_MCE API, but Firecracker doesn't use it.
299+
// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/x86.c?h=v4.14.311#n2553
300+
MSR_RANGE!(MSR_IA32_MCG_CTL),
301+
// Firecarcker is not tested with nested virtualization. Some CPU templates intentionally
302+
// disable nested virtualization. If nested virtualization is disabled, VMX-related MSRs cannot
303+
// be dumped. It can be seen in the following link that VMX-related MSRs depend on whether
304+
// nested virtualization is allowed.
305+
// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/vmx/vmx.c?h=v5.10.176#n1950
306+
// - MSR_IA32_VMX_BASIC (0x480)
307+
// - MSR_IA32_VMX_PINBASED_CTLS (0x481)
308+
// - MSR_IA32_VMX_PROCBASED_CTLS (0x482)
309+
// - MSR_IA32_VMX_EXIT_CTLS (0x483)
310+
// - MSR_IA32_VMX_ENTRY_CTLS (0x484)
311+
// - MSR_IA32_VMX_MISC (0x485)
312+
// - MSR_IA32_VMX_CR0_FIXED0 (0x486)
313+
// - MSR_IA32_VMX_CR0_FIXED1 (0x487)
314+
// - MSR_IA32_VMX_CR4_FIXED0 (0x488)
315+
// - MSR_IA32_VMX_CR4_FIXED1 (0x489)
316+
// - MSR_IA32_VMX_VMCS_ENUM (0x48A)
317+
// - MSR_IA32_VMX_PROCBASED_CTLS2 (0x48B)
318+
// - MSR_IA32_VMX_EPT_VPID_CAP (0x48C)
319+
// - MSR_IA32_VMX_TRUE_PINBASED_CTLS (0x48D)
320+
// - MSR_IA32_VMX_TRUE_PROCBASED_CTLS (0x48E)
321+
// - MSR_IA32_VMX_TRUE_EXIT_CTLS (0x48F)
322+
// - MSR_IA32_VMX_TRUE_ENTRY_CTLS (0x490)
323+
// - MSR_IA32_VMX_VMFUNC (0x491)
351324
MSR_RANGE!(MSR_IA32_VMX_BASIC, 18),
352-
// MSR_IA32_MCG_STATUS
353-
// MSR_IA32_MCG_CTL
354-
MSR_RANGE!(MSR_IA32_MCG_STATUS, 2),
355-
// MSR_IA32_MCG_EXT_CTL
356-
MSR_RANGE!(MSR_IA32_MCG_EXT_CTL),
357-
// HV_X64_MSR_GUEST_OS_ID
358-
// HV_X64_MSR_HYPERCALL
359-
// HV_X64_MSR_VP_INDEX
360-
// HV_X64_MSR_RESET
325+
// Firecracker doesn't work with Hyper-V. KVM_GET_MSRS fails on kernel 4.14 because it doesn't
326+
// have the following patch.
327+
// https://github.com/torvalds/linux/commit/44883f01fe6ae436a8604c47d8435276fef369b0
328+
// - HV_X64_MSR_GUEST_OS_ID (0x40000000)
329+
// - HV_X64_MSR_HYPERCALL (0x40000001)
330+
// - HV_X64_MSR_VP_INDEX (0x40000002)
331+
// - HV_X64_MSR_RESET (0x40000003)
332+
// - HV_X64_MSR_VP_RUNTIME (0x40000010)
333+
// - HV_X64_MSR_TIME_REF_COUNT (0x40000020)
334+
// - HV_X64_MSR_REFERENCE_TSC (0x40000021)
335+
// - HV_X64_MSR_TSC_FREQUENCY (0x40000022)
336+
// - HV_X64_MSR_APIC_FREQUENCY (0x40000023)
337+
// - HV_X64_MSR_VP_ASSIST_PAGE (0x40000073)
338+
// - HV_X64_MSR_SCONTROL (0x40000080)
339+
// - HV_X64_MSR_STIMER0_CONFIG (0x400000b0)
340+
// - HV_X64_MSR_SYNDBG_CONTROL (0x400000f1)
341+
// - HV_X64_MSR_SYNDBG_STATUS (0x400000f2)
342+
// - HV_X64_MSR_SYNDBG_SEND_BUFFER (0x400000f3)
343+
// - HV_X64_MSR_SYNDBG_RECV_BUFFER (0x400000f4)
344+
// - HV_X64_MSR_SYNDBG_PENDING_BUFFER (0x400000f5)
345+
// - HV_X64_MSR_SYNDBG_OPTIONS (0x400000ff)
346+
// - HV_X64_MSR_CRASH_Pn (0x40000100..=0x40000104)
347+
// - HV_X64_MSR_CRASH_CTL (0x40000105)
348+
// - HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106)
349+
// - HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)
350+
// - HV_X64_MSR_TSC_EMULATION_STATUS (0x40000108)
351+
// - HV_X64_MSR_TSC_INVARIANT_CONTROL (0x40000118)
361352
MSR_RANGE!(HV_X64_MSR_GUEST_OS_ID, 4),
362-
// HV_X64_MSR_VP_RUNTIME
363353
MSR_RANGE!(HV_X64_MSR_VP_RUNTIME),
364-
// HV_X64_MSR_VP_ASSIST_PAGE
365-
MSR_RANGE!(HV_X64_MSR_VP_ASSIST_PAGE),
366-
// HV_X64_MSR_SCONTROL
354+
MSR_RANGE!(HV_X64_MSR_TIME_REF_COUNT, 4),
367355
MSR_RANGE!(HV_X64_MSR_SCONTROL),
368-
// HV_X64_MSR_STIMER0_CONFIG
356+
MSR_RANGE!(HV_X64_MSR_VP_ASSIST_PAGE),
369357
MSR_RANGE!(HV_X64_MSR_STIMER0_CONFIG),
370-
// HV_X64_MSR_CRASH_Pn
371-
// HV_X64_MSR_CRASH_CTL
372-
MSR_RANGE!(HV_X64_MSR_CRASH_P0, 6),
373-
// HV_X64_MSR_REENLIGHTENMENT_CONTROL
374-
// HV_X64_MSR_TSC_EMULATION_CONTROL
375-
// HV_X64_MSR_TSC_EMULATION_STATUS
376-
MSR_RANGE!(HV_X64_MSR_REENLIGHTENMENT_CONTROL, 3),
377-
// HV_X64_MSR_TIME_REF_COUNT
378-
// HV_X64_MSR_REFERENCE_TSC
379-
// HV_X64_MSR_TSC_FREQUENCY
380-
// HV_X64_MSR_APIC_FREQUENCY
381-
MSR_RANGE!(HV_X64_MSR_TIME_REF_COUNT, 4),
382-
// HV_X64_MSR_SYNDBG_CONTROL
383-
// HV_X64_MSR_SYNDBG_STATUS
384-
// HV_X64_MSR_SYNDBG_SEND_BUFFER
385-
// HV_X64_MSR_SYNDBG_RECV_BUFFER
386-
// HV_X64_MSR_SYNDBG_PENDING_BUFFER
387358
MSR_RANGE!(HV_X64_MSR_SYNDBG_CONTROL, 5),
388-
// HV_X64_MSR_SYNDBG_OPTIONS
389359
MSR_RANGE!(HV_X64_MSR_SYNDBG_OPTIONS),
390-
// HV_X64_MSR_TSC_INVARIANT_CONTROL
360+
MSR_RANGE!(HV_X64_MSR_CRASH_P0, 6),
361+
MSR_RANGE!(HV_X64_MSR_REENLIGHTENMENT_CONTROL, 3),
391362
MSR_RANGE!(HV_X64_MSR_TSC_INVARIANT_CONTROL),
392363
];
393364

394-
/// Specifies whether a particular MSR should be dumped.
365+
/// Checks whether a particular MSR can be dumped.
395366
///
396367
/// # Arguments
397368
///
398369
/// * `index` - The index of the MSR that is checked whether it's needed for serialization.
399-
pub fn msr_should_dump(index: u32) -> bool {
370+
pub fn msr_is_dumpable(index: u32) -> bool {
400371
!UNDUMPABLE_MSR_RANGES
401372
.iter()
402373
.any(|range| range.contains(index))
403374
}
404375

405-
/// List of MSRs that should not be included in the dump of CPU configuration on AMD.
406-
static UNDUMPABLE_MSR_RANGES_AMD: &[MsrRange] = &[
407-
// MSR_IA32_ARCH_CAPABILITIES has been emulated by KVM since kernel 5.7.
408-
// https://github.com/torvalds/linux/commit/93c380e7b528882396ca463971012222bad7d82e
409-
// https://lore.kernel.org/all/[email protected]/
410-
// As this MSR is not available on AMD originally, Firecracker disables it explicitly by
411-
// setting 0 to CPUID.(EAX=07H,ECX=0):EDX[bit 29]. Thus, this MSR should be removed from the
412-
// dump on AMD.
413-
MSR_RANGE!(MSR_IA32_ARCH_CAPABILITIES),
414-
];
415-
416-
/// Specifies whether a particular MSR should be dumped on AMD
417-
///
418-
/// # Arguments
419-
///
420-
/// * `index` - The index of the MSR that is checked whether it's needed for serialization.
421-
pub fn msr_should_dump_amd(index: u32) -> bool {
422-
!UNDUMPABLE_MSR_RANGES_AMD
423-
.iter()
424-
.any(|range| range.contains(index))
425-
}
426-
427376
/// Returns the list of dumpable MSR indices.
428377
///
429378
/// # Arguments
@@ -439,11 +388,7 @@ pub fn get_msrs_to_dump(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
439388
.get_msr_index_list()
440389
.map_err(MsrError::GetMsrIndexList)?;
441390

442-
msr_index_list.retain(|msr_index| msr_should_dump(*msr_index));
443-
if &get_vendor_id_from_host()? == VENDOR_ID_AMD {
444-
msr_index_list.retain(|msr_index| msr_should_dump_amd(*msr_index));
445-
}
446-
391+
msr_index_list.retain(|msr_index| msr_is_dumpable(*msr_index));
447392
Ok(msr_index_list)
448393
}
449394

@@ -526,16 +471,7 @@ mod tests {
526471
fn test_msr_list_to_dump() {
527472
for range in UNDUMPABLE_MSR_RANGES.iter() {
528473
for msr in range.base..(range.base + range.nmsrs) {
529-
assert!(!msr_should_dump(msr));
530-
}
531-
}
532-
}
533-
534-
#[test]
535-
fn test_msr_list_to_dump_amd() {
536-
for range in UNDUMPABLE_MSR_RANGES_AMD.iter() {
537-
for msr in range.base..(range.base + range.nmsrs) {
538-
assert!(!msr_should_dump_amd(msr));
474+
assert!(!msr_is_dumpable(msr));
539475
}
540476
}
541477
}

0 commit comments

Comments
 (0)