@@ -10,8 +10,7 @@ use crate::arch_gen::x86::hyperv::*;
10
10
use crate :: arch_gen:: x86:: hyperv_tlfs:: * ;
11
11
use crate :: arch_gen:: x86:: msr_index:: * ;
12
12
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 ;
15
14
16
15
#[ derive( Debug , PartialEq , Eq , thiserror:: Error , displaydoc:: Display ) ]
17
16
/// MSR related errors.
@@ -271,159 +270,109 @@ pub fn get_msrs_to_save(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
271
270
Ok ( msr_index_list)
272
271
}
273
272
274
- // List of MSRs that should not be included in the dump of CPU configuration .
273
+ // List of MSRs that cannot be dumped .
275
274
//
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.
282
279
// 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
283
280
//
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`).
303
283
// 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
317
292
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)
351
324
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)
361
352
MSR_RANGE ! ( HV_X64_MSR_GUEST_OS_ID , 4 ) ,
362
- // HV_X64_MSR_VP_RUNTIME
363
353
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 ) ,
367
355
MSR_RANGE ! ( HV_X64_MSR_SCONTROL ) ,
368
- // HV_X64_MSR_STIMER0_CONFIG
356
+ MSR_RANGE ! ( HV_X64_MSR_VP_ASSIST_PAGE ) ,
369
357
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
387
358
MSR_RANGE ! ( HV_X64_MSR_SYNDBG_CONTROL , 5 ) ,
388
- // HV_X64_MSR_SYNDBG_OPTIONS
389
359
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 ) ,
391
362
MSR_RANGE ! ( HV_X64_MSR_TSC_INVARIANT_CONTROL ) ,
392
363
] ;
393
364
394
- /// Specifies whether a particular MSR should be dumped.
365
+ /// Checks whether a particular MSR can be dumped.
395
366
///
396
367
/// # Arguments
397
368
///
398
369
/// * `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 {
400
371
!UNDUMPABLE_MSR_RANGES
401
372
. iter ( )
402
373
. any ( |range| range. contains ( index) )
403
374
}
404
375
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
-
427
376
/// Returns the list of dumpable MSR indices.
428
377
///
429
378
/// # Arguments
@@ -439,11 +388,7 @@ pub fn get_msrs_to_dump(kvm_fd: &Kvm) -> Result<MsrList, MsrError> {
439
388
. get_msr_index_list ( )
440
389
. map_err ( MsrError :: GetMsrIndexList ) ?;
441
390
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) ) ;
447
392
Ok ( msr_index_list)
448
393
}
449
394
@@ -526,16 +471,7 @@ mod tests {
526
471
fn test_msr_list_to_dump ( ) {
527
472
for range in UNDUMPABLE_MSR_RANGES . iter ( ) {
528
473
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) ) ;
539
475
}
540
476
}
541
477
}
0 commit comments