vmm/arch/x86_64/
msr.rs

1// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/// Model Specific Registers (MSRs) related functionality.
5use bitflags::bitflags;
6use kvm_bindings::{MsrList, Msrs, kvm_msr_entry};
7use kvm_ioctls::{Kvm, VcpuFd};
8
9use crate::arch::x86_64::generated::hyperv::*;
10use crate::arch::x86_64::generated::hyperv_tlfs::*;
11use crate::arch::x86_64::generated::msr_index::*;
12use crate::arch::x86_64::generated::perf_event::*;
13use crate::cpu_config::x86_64::cpuid::common::GetCpuidError;
14
15#[derive(Debug, PartialEq, Eq, thiserror::Error, displaydoc::Display)]
16/// MSR related errors.
17pub enum MsrError {
18    /// Failed to create `vmm_sys_util::fam::FamStructWrapper` for MSRs
19    Fam(#[from] vmm_sys_util::fam::Error),
20    /// Failed to get MSR index list: {0}
21    GetMsrIndexList(kvm_ioctls::Error),
22    /// Invalid CPU vendor: {0}
23    InvalidVendor(#[from] GetCpuidError),
24    /// Failed to set MSRs: {0}
25    SetMsrs(kvm_ioctls::Error),
26    /// Not all given MSRs were set.
27    SetMsrsIncomplete,
28}
29
30/// MSR range
31#[derive(Debug)]
32pub struct MsrRange {
33    /// Base MSR address
34    pub base: u32,
35    /// Number of MSRs
36    pub nmsrs: u32,
37}
38
39impl MsrRange {
40    /// Returns whether `msr` is contained in this MSR range.
41    pub fn contains(&self, msr: u32) -> bool {
42        self.base <= msr && msr < self.base + self.nmsrs
43    }
44}
45
46/// Base MSR for APIC
47const APIC_BASE_MSR: u32 = 0x800;
48
49/// Number of APIC MSR indexes
50const APIC_MSR_INDEXES: u32 = 0x400;
51
52/// Custom MSRs fall in the range 0x4b564d00-0x4b564dff
53const MSR_KVM_WALL_CLOCK_NEW: u32 = 0x4b56_4d00;
54const MSR_KVM_SYSTEM_TIME_NEW: u32 = 0x4b56_4d01;
55const MSR_KVM_ASYNC_PF_EN: u32 = 0x4b56_4d02;
56const MSR_KVM_STEAL_TIME: u32 = 0x4b56_4d03;
57const MSR_KVM_PV_EOI_EN: u32 = 0x4b56_4d04;
58const MSR_KVM_POLL_CONTROL: u32 = 0x4b56_4d05;
59const MSR_KVM_ASYNC_PF_INT: u32 = 0x4b56_4d06;
60
61/// Taken from arch/x86/include/asm/msr-index.h
62/// Spectre mitigations control MSR
63pub const MSR_IA32_SPEC_CTRL: u32 = 0x0000_0048;
64/// Architecture capabilities MSR
65pub const MSR_IA32_ARCH_CAPABILITIES: u32 = 0x0000_010a;
66
67const MSR_IA32_PRED_CMD: u32 = 0x0000_0049;
68
69bitflags! {
70    /// Feature flags enumerated in the IA32_ARCH_CAPABILITIES MSR.
71    /// See https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/cpuid-enumeration-and-architectural-msrs.html
72    #[derive(Default)]
73    #[repr(C)]
74    pub struct ArchCapaMSRFlags: u64 {
75        /// The processor is not susceptible to Rogue Data Cache Load (RDCL).
76        const RDCL_NO               = 1 << 0;
77        /// The processor supports enhanced Indirect Branch Restriction Speculation (IBRS)
78        const IBRS_ALL              = 1 << 1;
79        /// The processor supports RSB Alternate. Alternative branch predictors may be used by RET instructions
80        /// when the RSB is empty. Software using retpoline may be affected by this behavior.
81        const RSBA                  = 1 << 2;
82        /// A value of 1 indicates the hypervisor need not flush the L1D on VM entry.
83        const SKIP_L1DFL_VMENTRY    = 1 << 3;
84        /// Processor is not susceptible to Speculative Store Bypass (SSB).
85        const SSB_NO                = 1 << 4;
86        /// Processor is not susceptible to Microarchitectural Data Sampling (MDS).
87        const MDS_NO                = 1 << 5;
88        /// The processor is not susceptible to a machine check error due to modifying the size of a code page
89        /// without TLB invalidation.
90        const IF_PSCHANGE_MC_NO     = 1 << 6;
91        /// The processor supports RTM_DISABLE and TSX_CPUID_CLEAR.
92        const TSX_CTRL              = 1 << 7;
93        /// Processor is not susceptible to IntelĀ® Transactional Synchronization Extensions
94        /// (IntelĀ® TSX) Asynchronous Abort (TAA).
95        const TAA_NO                = 1 << 8;
96        // Bit 9 is reserved
97        /// Processor supports IA32_MISC_PACKAGE_CTRLS MSR.
98        const MISC_PACKAGE_CTRLS    = 1 << 10;
99        /// Processor supports setting and reading IA32_MISC_PACKAGE_CTLS[0] (ENERGY_FILTERING_ENABLE) bit.
100        const ENERGY_FILTERING_CTL  = 1 << 11;
101        /// The processor supports data operand independent timing mode.
102        const DOITM                 = 1 << 12;
103        /// The processor is not affected by either the Shared Buffers Data Read (SBDR) vulnerability or the
104        /// Sideband Stale Data Propagator (SSDP).
105        const SBDR_SSDP_NO          = 1 << 13;
106        /// The processor is not affected by the Fill Buffer Stale Data Propagator (FBSDP).
107        const FBSDP_NO              = 1 << 14;
108        /// The processor is not affected by vulnerabilities involving the Primary Stale Data Propagator (PSDP).
109        const PSDP_NO               = 1 << 15;
110        // Bit 16 is reserved
111        /// The processor will overwrite fill buffer values as part of MD_CLEAR operations with the VERW instruction.
112        /// On these processors, L1D_FLUSH does not overwrite fill buffer values.
113        const FB_CLEAR              = 1 << 17;
114        /// The processor supports read and write to the IA32_MCU_OPT_CTRL MSR (MSR 123H) and to the FB_CLEAR_DIS bit
115        /// in that MSR (bit position 3).
116        const FB_CLEAR_CTRL         = 1 << 18;
117        /// A value of 1 indicates processor may have the RRSBA alternate prediction behavior,
118        /// if not disabled by RRSBA_DIS_U or RRSBA_DIS_S.
119        const RRSBA                 = 1 << 19;
120        /// A value of 1 indicates BHI_NO branch prediction behavior,
121        /// regardless of the value of IA32_SPEC_CTRL[BHI_DIS_S] MSR bit.
122        const BHI_NO                = 1 << 20;
123        // Bits 21:22 are reserved
124        /// If set, the IA32_OVERCLOCKING STATUS MSR exists.
125        const OVERCLOCKING_STATUS   = 1 << 23;
126        // Bits 24:63 are reserved
127    }
128}
129
130/// Macro for generating a MsrRange.
131#[macro_export]
132macro_rules! MSR_RANGE {
133    ($base:expr, $nmsrs:expr) => {
134        MsrRange {
135            base: $base,
136            nmsrs: $nmsrs,
137        }
138    };
139    ($base:expr) => {
140        MSR_RANGE!($base, 1)
141    };
142}
143
144// List of MSRs that can be serialized. List is sorted in ascending order of MSRs addresses.
145static SERIALIZABLE_MSR_RANGES: &[MsrRange] = &[
146    MSR_RANGE!(MSR_IA32_P5_MC_ADDR),
147    MSR_RANGE!(MSR_IA32_P5_MC_TYPE),
148    MSR_RANGE!(MSR_IA32_TSC),
149    MSR_RANGE!(MSR_IA32_PLATFORM_ID),
150    MSR_RANGE!(MSR_IA32_APICBASE),
151    MSR_RANGE!(MSR_IA32_EBL_CR_POWERON),
152    MSR_RANGE!(MSR_EBC_FREQUENCY_ID),
153    MSR_RANGE!(MSR_SMI_COUNT),
154    MSR_RANGE!(MSR_IA32_FEAT_CTL),
155    MSR_RANGE!(MSR_IA32_TSC_ADJUST),
156    MSR_RANGE!(MSR_IA32_SPEC_CTRL),
157    MSR_RANGE!(MSR_IA32_PRED_CMD),
158    MSR_RANGE!(MSR_IA32_UCODE_WRITE),
159    MSR_RANGE!(MSR_IA32_UCODE_REV),
160    MSR_RANGE!(MSR_IA32_SMBASE),
161    MSR_RANGE!(MSR_FSB_FREQ),
162    MSR_RANGE!(MSR_PLATFORM_INFO),
163    MSR_RANGE!(MSR_PKG_CST_CONFIG_CONTROL),
164    MSR_RANGE!(MSR_IA32_MPERF),
165    MSR_RANGE!(MSR_IA32_APERF),
166    MSR_RANGE!(MSR_MTRRcap),
167    MSR_RANGE!(MSR_IA32_BBL_CR_CTL3),
168    MSR_RANGE!(MSR_IA32_SYSENTER_CS),
169    MSR_RANGE!(MSR_IA32_SYSENTER_ESP),
170    MSR_RANGE!(MSR_IA32_SYSENTER_EIP),
171    MSR_RANGE!(MSR_IA32_MCG_CAP),
172    MSR_RANGE!(MSR_IA32_MCG_STATUS),
173    MSR_RANGE!(MSR_IA32_MCG_CTL),
174    MSR_RANGE!(MSR_IA32_PERF_STATUS),
175    MSR_RANGE!(MSR_IA32_MISC_ENABLE),
176    MSR_RANGE!(MSR_MISC_FEATURE_CONTROL),
177    MSR_RANGE!(MSR_MISC_PWR_MGMT),
178    MSR_RANGE!(MSR_TURBO_RATIO_LIMIT),
179    MSR_RANGE!(MSR_TURBO_RATIO_LIMIT1),
180    MSR_RANGE!(MSR_IA32_DEBUGCTLMSR),
181    MSR_RANGE!(MSR_IA32_LASTBRANCHFROMIP),
182    MSR_RANGE!(MSR_IA32_LASTBRANCHTOIP),
183    MSR_RANGE!(MSR_IA32_LASTINTFROMIP),
184    MSR_RANGE!(MSR_IA32_LASTINTTOIP),
185    MSR_RANGE!(MSR_IA32_POWER_CTL),
186    MSR_RANGE!(
187        // IA32_MTRR_PHYSBASE0
188        0x200, 0x100
189    ),
190    MSR_RANGE!(
191        // MSR_CORE_C3_RESIDENCY
192        // MSR_CORE_C6_RESIDENCY
193        // MSR_CORE_C7_RESIDENCY
194        MSR_CORE_C3_RESIDENCY,
195        3
196    ),
197    MSR_RANGE!(MSR_IA32_MC0_CTL, 0x80),
198    MSR_RANGE!(MSR_RAPL_POWER_UNIT),
199    MSR_RANGE!(
200        // MSR_PKGC3_IRTL
201        // MSR_PKGC6_IRTL
202        // MSR_PKGC7_IRTL
203        MSR_PKGC3_IRTL,
204        3
205    ),
206    MSR_RANGE!(MSR_PKG_POWER_LIMIT),
207    MSR_RANGE!(MSR_PKG_ENERGY_STATUS),
208    MSR_RANGE!(MSR_PKG_PERF_STATUS),
209    MSR_RANGE!(MSR_PKG_POWER_INFO),
210    MSR_RANGE!(MSR_DRAM_POWER_LIMIT),
211    MSR_RANGE!(MSR_DRAM_ENERGY_STATUS),
212    MSR_RANGE!(MSR_DRAM_PERF_STATUS),
213    MSR_RANGE!(MSR_DRAM_POWER_INFO),
214    MSR_RANGE!(MSR_CONFIG_TDP_NOMINAL),
215    MSR_RANGE!(MSR_CONFIG_TDP_LEVEL_1),
216    MSR_RANGE!(MSR_CONFIG_TDP_LEVEL_2),
217    MSR_RANGE!(MSR_CONFIG_TDP_CONTROL),
218    MSR_RANGE!(MSR_TURBO_ACTIVATION_RATIO),
219    MSR_RANGE!(MSR_IA32_TSC_DEADLINE),
220    MSR_RANGE!(APIC_BASE_MSR, APIC_MSR_INDEXES),
221    MSR_RANGE!(MSR_KVM_WALL_CLOCK_NEW),
222    MSR_RANGE!(MSR_KVM_SYSTEM_TIME_NEW),
223    MSR_RANGE!(MSR_KVM_ASYNC_PF_EN),
224    MSR_RANGE!(MSR_KVM_STEAL_TIME),
225    MSR_RANGE!(MSR_KVM_PV_EOI_EN),
226    MSR_RANGE!(MSR_EFER),
227    MSR_RANGE!(MSR_STAR),
228    MSR_RANGE!(MSR_LSTAR),
229    MSR_RANGE!(MSR_CSTAR),
230    MSR_RANGE!(MSR_SYSCALL_MASK),
231    MSR_RANGE!(MSR_FS_BASE),
232    MSR_RANGE!(MSR_GS_BASE),
233    MSR_RANGE!(MSR_KERNEL_GS_BASE),
234    MSR_RANGE!(MSR_TSC_AUX),
235    MSR_RANGE!(MSR_MISC_FEATURES_ENABLES),
236    MSR_RANGE!(MSR_K7_HWCR),
237    MSR_RANGE!(MSR_KVM_POLL_CONTROL),
238    MSR_RANGE!(MSR_KVM_ASYNC_PF_INT),
239    MSR_RANGE!(MSR_IA32_TSX_CTRL),
240];
241
242/// Specifies whether a particular MSR should be included in vcpu serialization.
243///
244/// # Arguments
245///
246/// * `index` - The index of the MSR that is checked whether it's needed for serialization.
247pub fn msr_should_serialize(index: u32) -> bool {
248    // Denied MSR not exported by Linux: IA32_MCG_CTL
249    if index == MSR_IA32_MCG_CTL {
250        return false;
251    };
252    SERIALIZABLE_MSR_RANGES
253        .iter()
254        .any(|range| range.contains(index))
255}
256
257/// Returns the list of serializable MSR indices.
258///
259/// # Arguments
260///
261/// * `kvm_fd` - Ref to `kvm_ioctls::Kvm`.
262///
263/// # Errors
264///
265/// When:
266/// - [`kvm_ioctls::Kvm::get_msr_index_list()`] errors.
267pub fn get_msrs_to_save(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
268    let mut msr_index_list = kvm_fd
269        .get_msr_index_list()
270        .map_err(MsrError::GetMsrIndexList)?;
271    msr_index_list.retain(|msr_index| msr_should_serialize(*msr_index));
272    Ok(msr_index_list)
273}
274
275// List of MSRs that cannot be dumped.
276//
277// KVM_GET_MSR_INDEX_LIST returns some MSR indices that KVM_GET_MSRS fails to get depending on
278// configuration. For example, Firecracker disables PMU by default in CPUID normalization for CPUID
279// leaf 0xA. Due to this, some PMU-related MSRs cannot be retrieved via KVM_GET_MSRS. The dependency
280// on CPUID leaf 0xA can be found in the following link.
281// 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
282//
283// The list of MSR indices returned by KVM_GET_MSR_INDEX_LIST can be found in the following link
284// (`msrs_to_save_all` + `num_emulated_msrs`).
285// https://elixir.bootlin.com/linux/v5.10.176/source/arch/x86/kvm/x86.c#L1211
286const UNDUMPABLE_MSR_RANGES: [MsrRange; 17] = [
287    // - MSR_ARCH_PERFMON_FIXED_CTRn (0x309..=0x30C): CPUID.0Ah:EDX[0:4] > 0
288    MSR_RANGE!(MSR_ARCH_PERFMON_FIXED_CTR0, 4),
289    // - MSR_CORE_PERF_FIXED_CTR_CTRL (0x38D): CPUID:0Ah:EAX[7:0] > 1
290    // - MSR_CORE_PERF_GLOBAL_STATUS (0x38E): CPUID:0Ah:EAX[7:0] > 0 ||
291    //   (CPUID.(EAX=07H,ECX=0):EBX[25] = 1 && CPUID.(EAX=014H,ECX=0):ECX[0] = 1)
292    // - MSR_CORE_PERF_GLOBAL_CTRL (0x39F): CPUID.0AH: EAX[7:0] > 0
293    // - MSR_CORE_PERF_GLOBAL_OVF_CTRL (0x390): CPUID.0AH: EAX[7:0] > 0 && CPUID.0AH: EAX[7:0] <= 3
294    MSR_RANGE!(MSR_CORE_PERF_FIXED_CTR_CTRL, 4),
295    // - MSR_ARCH_PERFMON_PERFCTRn (0xC1..=0xC8): CPUID.0AH:EAX[15:8] > 0
296    MSR_RANGE!(MSR_ARCH_PERFMON_PERFCTR0, 8),
297    // - MSR_ARCH_PERFMON_EVENTSELn (0x186..=0x18D): CPUID.0AH:EAX[15:8] > 0
298    MSR_RANGE!(MSR_ARCH_PERFMON_EVENTSEL0, 8),
299    // On kernel 4.14, IA32_MCG_CTL (0x17B) can be retrieved only if IA32_MCG_CAP.CTL_P[8] = 1 for
300    // vCPU. IA32_MCG_CAP can be set up via KVM_X86_SETUP_MCE API, but Firecracker doesn't use it.
301    // https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/x86.c?h=v4.14.311#n2553
302    MSR_RANGE!(MSR_IA32_MCG_CTL),
303    // Firecracker is not tested with nested virtualization. Some CPU templates intentionally
304    // disable nested virtualization. If nested virtualization is disabled, VMX-related MSRs cannot
305    // be dumped. It can be seen in the following link that VMX-related MSRs depend on whether
306    // nested virtualization is allowed.
307    // https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/kvm/vmx/vmx.c?h=v5.10.176#n1950
308    // - MSR_IA32_VMX_BASIC (0x480)
309    // - MSR_IA32_VMX_PINBASED_CTLS (0x481)
310    // - MSR_IA32_VMX_PROCBASED_CTLS (0x482)
311    // - MSR_IA32_VMX_EXIT_CTLS (0x483)
312    // - MSR_IA32_VMX_ENTRY_CTLS (0x484)
313    // - MSR_IA32_VMX_MISC (0x485)
314    // - MSR_IA32_VMX_CR0_FIXED0 (0x486)
315    // - MSR_IA32_VMX_CR0_FIXED1 (0x487)
316    // - MSR_IA32_VMX_CR4_FIXED0 (0x488)
317    // - MSR_IA32_VMX_CR4_FIXED1 (0x489)
318    // - MSR_IA32_VMX_VMCS_ENUM (0x48A)
319    // - MSR_IA32_VMX_PROCBASED_CTLS2 (0x48B)
320    // - MSR_IA32_VMX_EPT_VPID_CAP (0x48C)
321    // - MSR_IA32_VMX_TRUE_PINBASED_CTLS (0x48D)
322    // - MSR_IA32_VMX_TRUE_PROCBASED_CTLS (0x48E)
323    // - MSR_IA32_VMX_TRUE_EXIT_CTLS (0x48F)
324    // - MSR_IA32_VMX_TRUE_ENTRY_CTLS (0x490)
325    // - MSR_IA32_VMX_VMFUNC (0x491)
326    MSR_RANGE!(MSR_IA32_VMX_BASIC, 18),
327    // Firecracker doesn't work with Hyper-V. KVM_GET_MSRS fails on kernel 4.14 because it doesn't
328    // have the following patch.
329    // https://github.com/torvalds/linux/commit/44883f01fe6ae436a8604c47d8435276fef369b0
330    // - HV_X64_MSR_GUEST_OS_ID (0x40000000)
331    // - HV_X64_MSR_HYPERCALL (0x40000001)
332    // - HV_X64_MSR_VP_INDEX (0x40000002)
333    // - HV_X64_MSR_RESET (0x40000003)
334    // - HV_X64_MSR_VP_RUNTIME (0x40000010)
335    // - HV_X64_MSR_TIME_REF_COUNT (0x40000020)
336    // - HV_X64_MSR_REFERENCE_TSC (0x40000021)
337    // - HV_X64_MSR_TSC_FREQUENCY (0x40000022)
338    // - HV_X64_MSR_APIC_FREQUENCY (0x40000023)
339    // - HV_X64_MSR_VP_ASSIST_PAGE (0x40000073)
340    // - HV_X64_MSR_SCONTROL (0x40000080)
341    // - HV_X64_MSR_STIMER0_CONFIG (0x400000b0)
342    // - HV_X64_MSR_SYNDBG_CONTROL (0x400000f1)
343    // - HV_X64_MSR_SYNDBG_STATUS (0x400000f2)
344    // - HV_X64_MSR_SYNDBG_SEND_BUFFER (0x400000f3)
345    // - HV_X64_MSR_SYNDBG_RECV_BUFFER (0x400000f4)
346    // - HV_X64_MSR_SYNDBG_PENDING_BUFFER (0x400000f5)
347    // - HV_X64_MSR_SYNDBG_OPTIONS (0x400000ff)
348    // - HV_X64_MSR_CRASH_Pn (0x40000100..=0x40000104)
349    // - HV_X64_MSR_CRASH_CTL (0x40000105)
350    // - HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106)
351    // - HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)
352    // - HV_X64_MSR_TSC_EMULATION_STATUS (0x40000108)
353    // - HV_X64_MSR_TSC_INVARIANT_CONTROL (0x40000118)
354    MSR_RANGE!(HV_X64_MSR_GUEST_OS_ID, 4),
355    MSR_RANGE!(HV_X64_MSR_VP_RUNTIME),
356    MSR_RANGE!(HV_X64_MSR_TIME_REF_COUNT, 4),
357    MSR_RANGE!(HV_X64_MSR_SCONTROL),
358    MSR_RANGE!(HV_X64_MSR_VP_ASSIST_PAGE),
359    MSR_RANGE!(HV_X64_MSR_STIMER0_CONFIG),
360    MSR_RANGE!(HV_X64_MSR_SYNDBG_CONTROL, 5),
361    MSR_RANGE!(HV_X64_MSR_SYNDBG_OPTIONS),
362    MSR_RANGE!(HV_X64_MSR_CRASH_P0, 6),
363    MSR_RANGE!(HV_X64_MSR_REENLIGHTENMENT_CONTROL, 3),
364    MSR_RANGE!(HV_X64_MSR_TSC_INVARIANT_CONTROL),
365];
366
367/// Checks whether a particular MSR can be dumped.
368///
369/// # Arguments
370///
371/// * `index` - The index of the MSR that is checked whether it's needed for serialization.
372pub fn msr_is_dumpable(index: u32) -> bool {
373    !UNDUMPABLE_MSR_RANGES
374        .iter()
375        .any(|range| range.contains(index))
376}
377
378/// Returns the list of dumpable MSR indices.
379///
380/// # Arguments
381///
382/// * `kvm_fd` - Ref to `Kvm`
383///
384/// # Errors
385///
386/// When:
387/// - [`kvm_ioctls::Kvm::get_msr_index_list()`] errors.
388pub fn get_msrs_to_dump(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
389    let mut msr_index_list = kvm_fd
390        .get_msr_index_list()
391        .map_err(MsrError::GetMsrIndexList)?;
392
393    msr_index_list.retain(|msr_index| msr_is_dumpable(*msr_index));
394    Ok(msr_index_list)
395}
396
397/// Creates and populates required MSR entries for booting Linux on X86_64.
398pub fn create_boot_msr_entries() -> Vec<kvm_msr_entry> {
399    let msr_entry_default = |msr| kvm_msr_entry {
400        index: msr,
401        data: 0x0,
402        ..Default::default()
403    };
404
405    vec![
406        msr_entry_default(MSR_IA32_SYSENTER_CS),
407        msr_entry_default(MSR_IA32_SYSENTER_ESP),
408        msr_entry_default(MSR_IA32_SYSENTER_EIP),
409        // x86_64 specific msrs, we only run on x86_64 not x86.
410        msr_entry_default(MSR_STAR),
411        msr_entry_default(MSR_CSTAR),
412        msr_entry_default(MSR_KERNEL_GS_BASE),
413        msr_entry_default(MSR_SYSCALL_MASK),
414        msr_entry_default(MSR_LSTAR),
415        // end of x86_64 specific code
416        msr_entry_default(MSR_IA32_TSC),
417        kvm_msr_entry {
418            index: MSR_IA32_MISC_ENABLE,
419            data: u64::from(MSR_IA32_MISC_ENABLE_FAST_STRING),
420            ..Default::default()
421        },
422        // set default memory type for physical memory outside configured
423        // memory ranges to write-back by setting MTRR enable bit (11) and
424        // setting memory type to write-back (value 6).
425        // https://wiki.osdev.org/MTRR
426        kvm_msr_entry {
427            index: MSR_MTRRdefType,
428            data: (1 << 11) | 0x6,
429            ..Default::default()
430        },
431    ]
432}
433
434/// Configure Model Specific Registers (MSRs) required to boot Linux for a given x86_64 vCPU.
435///
436/// # Arguments
437///
438/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
439///
440/// # Errors
441///
442/// When:
443/// - Failed to create [`vmm_sys_util::fam::FamStructWrapper`] for MSRs.
444/// - [`kvm_ioctls::ioctls::vcpu::VcpuFd::set_msrs`] errors.
445/// - [`kvm_ioctls::ioctls::vcpu::VcpuFd::set_msrs`] fails to write all given MSRs entries.
446pub fn set_msrs(vcpu: &VcpuFd, msr_entries: &[kvm_msr_entry]) -> Result<(), MsrError> {
447    let msrs = Msrs::from_entries(msr_entries)?;
448    vcpu.set_msrs(&msrs)
449        .map_err(MsrError::SetMsrs)
450        .and_then(|msrs_written| {
451            if msrs_written == msrs.as_fam_struct_ref().nmsrs as usize {
452                Ok(())
453            } else {
454                Err(MsrError::SetMsrsIncomplete)
455            }
456        })
457}
458
459#[cfg(test)]
460mod tests {
461    use kvm_ioctls::Kvm;
462
463    use super::*;
464
465    fn create_vcpu() -> VcpuFd {
466        let kvm = Kvm::new().unwrap();
467        let vm = kvm.create_vm().unwrap();
468        vm.create_vcpu(0).unwrap()
469    }
470
471    #[test]
472    fn test_msr_list_to_serialize() {
473        for range in SERIALIZABLE_MSR_RANGES.iter() {
474            for msr in range.base..(range.base + range.nmsrs) {
475                let should = !matches!(msr, MSR_IA32_MCG_CTL);
476                assert_eq!(msr_should_serialize(msr), should);
477            }
478        }
479    }
480
481    #[test]
482    fn test_msr_list_to_dump() {
483        for range in UNDUMPABLE_MSR_RANGES.iter() {
484            for msr in range.base..(range.base + range.nmsrs) {
485                assert!(!msr_is_dumpable(msr));
486            }
487        }
488    }
489
490    #[test]
491    #[allow(clippy::cast_ptr_alignment)]
492    fn test_setup_msrs() {
493        let vcpu = create_vcpu();
494        let msr_boot_entries = create_boot_msr_entries();
495        set_msrs(&vcpu, &msr_boot_entries).unwrap();
496
497        // This test will check against the last MSR entry configured (the tenth one).
498        // See create_msr_entries() for details.
499        let test_kvm_msrs_entry = [kvm_msr_entry {
500            index: MSR_IA32_MISC_ENABLE,
501            ..Default::default()
502        }];
503        let mut kvm_msrs_wrapper = Msrs::from_entries(&test_kvm_msrs_entry).unwrap();
504
505        // Get_msrs() returns the number of msrs that it succeed in reading.
506        // We only want to read one in this test case scenario.
507        let read_nmsrs = vcpu.get_msrs(&mut kvm_msrs_wrapper).unwrap();
508        // Validate it only read one.
509        assert_eq!(read_nmsrs, 1);
510
511        // Official entries that were setup when we did setup_msrs. We need to assert that the
512        // tenth one (i.e the one with index MSR_IA32_MISC_ENABLE has the data we
513        // expect.
514        let entry_vec = create_boot_msr_entries();
515        assert_eq!(entry_vec[9], kvm_msrs_wrapper.as_slice()[0]);
516    }
517
518    #[test]
519    fn test_set_valid_msrs() {
520        // Test `set_msrs()` with a valid MSR entry. It should succeed, as IA32_TSC MSR is listed
521        // in supported MSRs as of now.
522        let vcpu = create_vcpu();
523        let msr_entries = vec![kvm_msr_entry {
524            index: MSR_IA32_TSC,
525            data: 0,
526            ..Default::default()
527        }];
528        set_msrs(&vcpu, &msr_entries).unwrap();
529    }
530
531    #[test]
532    fn test_set_invalid_msrs() {
533        // Test `set_msrs()` with an invalid MSR entry. It should fail, as MSR index 2 is not
534        // listed in supported MSRs as of now. If hardware vendor adds this MSR index and KVM
535        // supports this MSR, we need to change the index as needed.
536        let vcpu = create_vcpu();
537        let msr_entries = vec![kvm_msr_entry {
538            index: 2,
539            ..Default::default()
540        }];
541        assert_eq!(
542            set_msrs(&vcpu, &msr_entries).unwrap_err(),
543            MsrError::SetMsrsIncomplete
544        );
545    }
546}