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}