5
5
// Use of this source code is governed by a BSD-style license that can be
6
6
// found in the THIRD-PARTY file.
7
7
8
+ use std:: collections:: HashSet ;
8
9
use std:: fmt:: { Display , Formatter } ;
9
10
use std:: { fmt, result} ;
10
11
@@ -14,11 +15,11 @@ use arch::x86_64::regs::{SetupFpuError, SetupRegistersError, SetupSpecialRegiste
14
15
use cpuid:: { c3, filter_cpuid, msrs_to_save_by_cpuid, t2, t2s, VmSpec } ;
15
16
use kvm_bindings:: {
16
17
kvm_debugregs, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs,
17
- kvm_xsave, CpuId , MsrList , Msrs ,
18
+ kvm_xsave, CpuId , Msrs , KVM_MAX_MSR_ENTRIES ,
18
19
} ;
19
20
use kvm_ioctls:: { VcpuExit , VcpuFd } ;
20
21
use logger:: { error, warn, IncMetric , METRICS } ;
21
- use versionize:: { VersionMap , Versionize , VersionizeResult } ;
22
+ use versionize:: { VersionMap , Versionize , VersionizeError , VersionizeResult } ;
22
23
use versionize_derive:: Versionize ;
23
24
use vm_memory:: { Address , GuestAddress , GuestMemoryMmap } ;
24
25
@@ -216,7 +217,7 @@ pub struct KvmVcpu {
216
217
pub pio_bus : Option < devices:: Bus > ,
217
218
pub mmio_bus : Option < devices:: Bus > ,
218
219
219
- msr_list : MsrList ,
220
+ msr_list : HashSet < u32 > ,
220
221
}
221
222
222
223
impl KvmVcpu {
@@ -234,7 +235,7 @@ impl KvmVcpu {
234
235
fd : kvm_vcpu,
235
236
pio_bus : None ,
236
237
mmio_bus : None ,
237
- msr_list : vm. supported_msrs ( ) . clone ( ) ,
238
+ msr_list : vm. supported_msrs ( ) . as_slice ( ) . iter ( ) . copied ( ) . collect ( ) ,
238
239
} )
239
240
}
240
241
@@ -294,11 +295,7 @@ impl KvmVcpu {
294
295
// the extra MSRs that we need to save based on a dependency map.
295
296
let extra_msrs =
296
297
msrs_to_save_by_cpuid ( & cpuid) . map_err ( KvmVcpuConfigureError :: FilterCpuid ) ?;
297
- for msr in extra_msrs {
298
- self . msr_list
299
- . push ( msr)
300
- . map_err ( KvmVcpuConfigureError :: PushMsrEntries ) ?;
301
- }
298
+ self . msr_list . extend ( extra_msrs) ;
302
299
303
300
// TODO: Some MSRs depend on values of other MSRs. This dependency will need to
304
301
// be implemented. For now we define known dependencies statically in the CPU
@@ -310,11 +307,7 @@ impl KvmVcpu {
310
307
// to save at snapshot as well.
311
308
// C3 and T2 currently don't have extra MSRs to save/set
312
309
if vcpu_config. cpu_template == CpuFeaturesTemplate :: T2S {
313
- for msr in t2s:: msr_entries_to_save ( ) {
314
- self . msr_list
315
- . push ( * msr)
316
- . map_err ( KvmVcpuConfigureError :: PushMsrEntries ) ?;
317
- }
310
+ self . msr_list . extend ( t2s:: msr_entries_to_save ( ) ) ;
318
311
t2s:: update_msr_entries ( & mut msr_boot_entries) ;
319
312
}
320
313
// By this point we know that at snapshot, the list of MSRs we need to
@@ -367,17 +360,24 @@ impl KvmVcpu {
367
360
// GET_MSRS requires a pre-populated data structure to do something
368
361
// meaningful. For SET_MSRS it will then contain good data.
369
362
370
- // Build the list of MSRs we want to save.
371
- let num_msrs = self . msr_list . as_fam_struct_ref ( ) . nmsrs as usize ;
372
- let mut msrs = Msrs :: new ( num_msrs) . map_err ( Error :: Fam ) ?;
373
- {
374
- let indices = self . msr_list . as_slice ( ) ;
363
+ // Build the list of MSRs we want to save. Sometimes we need to save
364
+ // more than KVM_MAX_MSR_ENTRIES in the snapshot, so we use a Vec<Msrs>
365
+ // to allow an unlimited number.
366
+ let mut all_msrs: Vec < Msrs > = Vec :: new ( ) ;
367
+ let msr_list: Vec < & u32 > = self . msr_list . iter ( ) . collect ( ) ;
368
+
369
+ // KVM only supports getting KVM_MAX_MSR_ENTRIES at a time so chunk
370
+ // them up into `Msrs` so it's easy to pass to the ioctl.
371
+ for chunk in msr_list. chunks ( KVM_MAX_MSR_ENTRIES ) {
372
+ let mut msrs = Msrs :: new ( chunk. len ( ) ) . map_err ( Error :: Fam ) ?;
375
373
let msr_entries = msrs. as_mut_slice ( ) ;
376
- assert_eq ! ( indices . len( ) , msr_entries. len( ) ) ;
377
- for ( pos, index) in indices . iter ( ) . enumerate ( ) {
378
- msr_entries[ pos] . index = * index;
374
+ assert_eq ! ( chunk . len( ) , msr_entries. len( ) ) ;
375
+ for ( pos, index) in chunk . iter ( ) . enumerate ( ) {
376
+ msr_entries[ pos] . index = * * index;
379
377
}
378
+ all_msrs. push ( msrs) ;
380
379
}
380
+
381
381
let mp_state = self . fd . get_mp_state ( ) . map_err ( Error :: VcpuGetMpState ) ?;
382
382
let regs = self . fd . get_regs ( ) . map_err ( Error :: VcpuGetRegs ) ?;
383
383
let sregs = self . fd . get_sregs ( ) . map_err ( Error :: VcpuGetSregs ) ?;
@@ -392,9 +392,12 @@ impl KvmVcpu {
392
392
warn ! ( "TSC freq not available. Snapshot cannot be loaded on a different CPU model." ) ;
393
393
None
394
394
} ) ;
395
- let nmsrs = self . fd . get_msrs ( & mut msrs) . map_err ( Error :: VcpuGetMsrs ) ?;
396
- if nmsrs != num_msrs {
397
- return Err ( Error :: VcpuGetMSRSIncomplete ) ;
395
+ for msrs in all_msrs. iter_mut ( ) {
396
+ let expected_nmsrs = msrs. as_slice ( ) . len ( ) ;
397
+ let nmsrs = self . fd . get_msrs ( msrs) . map_err ( Error :: VcpuGetMsrs ) ?;
398
+ if nmsrs != expected_nmsrs {
399
+ return Err ( Error :: VcpuGetMSRSIncomplete ) ;
400
+ }
398
401
}
399
402
let vcpu_events = self
400
403
. fd
@@ -406,7 +409,8 @@ impl KvmVcpu {
406
409
. fd
407
410
. get_cpuid2 ( kvm_bindings:: KVM_MAX_CPUID_ENTRIES )
408
411
. map_err ( Error :: VcpuGetCpuid ) ?,
409
- msrs,
412
+ saved_msrs : all_msrs,
413
+ msrs : Msrs :: new ( 0 ) . map_err ( Error :: Fam ) ?,
410
414
debug_regs,
411
415
lapic,
412
416
mp_state,
@@ -486,10 +490,11 @@ impl KvmVcpu {
486
490
self . fd
487
491
. set_lapic ( & state. lapic )
488
492
. map_err ( Error :: VcpuSetLapic ) ?;
489
- let nmsrs = self . fd . set_msrs ( & state. msrs ) . map_err ( Error :: VcpuSetMsrs ) ?;
490
- let num_msrs = state. msrs . as_fam_struct_ref ( ) . nmsrs as usize ;
491
- if nmsrs < num_msrs {
492
- return Err ( Error :: VcpuSetMSRSIncomplete ) ;
493
+ for msrs in & state. saved_msrs {
494
+ let nmsrs = self . fd . set_msrs ( msrs) . map_err ( Error :: VcpuSetMsrs ) ?;
495
+ if nmsrs < msrs. as_fam_struct_ref ( ) . nmsrs as usize {
496
+ return Err ( Error :: VcpuSetMSRSIncomplete ) ;
497
+ }
493
498
}
494
499
self . fd
495
500
. set_vcpu_events ( & state. vcpu_events )
@@ -535,7 +540,10 @@ impl KvmVcpu {
535
540
// NOTICE: Any changes to this structure require a snapshot version bump.
536
541
pub struct VcpuState {
537
542
pub cpuid : CpuId ,
543
+ #[ version( end = 3 , default_fn = "default_msrs" ) ]
538
544
msrs : Msrs ,
545
+ #[ version( start = 3 , de_fn = "de_saved_msrs" , ser_fn = "ser_saved_msrs" ) ]
546
+ saved_msrs : Vec < Msrs > ,
539
547
debug_regs : kvm_debugregs ,
540
548
lapic : kvm_lapic_state ,
541
549
mp_state : kvm_mp_state ,
@@ -565,6 +573,43 @@ impl VcpuState {
565
573
566
574
Ok ( ( ) )
567
575
}
576
+
577
+ fn default_msrs ( _source_version : u16 ) -> Msrs {
578
+ // Safe to unwrap since Msrs::new() only returns an error if the number
579
+ // of elements exceeds KVM_MAX_MSR_ENTRIES
580
+ Msrs :: new ( 0 ) . unwrap ( )
581
+ }
582
+
583
+ fn de_saved_msrs ( & mut self , source_version : u16 ) -> VersionizeResult < ( ) > {
584
+ if source_version < 3 {
585
+ self . saved_msrs . push ( self . msrs . clone ( ) ) ;
586
+ }
587
+ Ok ( ( ) )
588
+ }
589
+
590
+ fn ser_saved_msrs ( & mut self , target_version : u16 ) -> VersionizeResult < ( ) > {
591
+ match self . saved_msrs . len ( ) {
592
+ 0 => Err ( VersionizeError :: Serialize (
593
+ "Cannot serialize MSRs because the MSR list is empty" . to_string ( ) ,
594
+ ) ) ,
595
+ 1 => {
596
+ if target_version < 3 {
597
+ self . msrs = self . saved_msrs [ 0 ] . clone ( ) ;
598
+ Ok ( ( ) )
599
+ } else {
600
+ Err ( VersionizeError :: Serialize ( format ! (
601
+ "Cannot serialize MSRs to target version {}" ,
602
+ target_version
603
+ ) ) )
604
+ }
605
+ }
606
+ _ => Err ( VersionizeError :: Serialize (
607
+ "Cannot serialize MSRs. The uVM state needs to save
608
+ more MSRs than the target snapshot version supports."
609
+ . to_string ( ) ,
610
+ ) ) ,
611
+ }
612
+ }
568
613
}
569
614
570
615
#[ cfg( test) ]
@@ -585,6 +630,7 @@ mod tests {
585
630
VcpuState {
586
631
cpuid : CpuId :: new ( 1 ) . unwrap ( ) ,
587
632
msrs : Msrs :: new ( 1 ) . unwrap ( ) ,
633
+ saved_msrs : vec ! [ Msrs :: new( 1 ) . unwrap( ) ] ,
588
634
debug_regs : Default :: default ( ) ,
589
635
lapic : Default :: default ( ) ,
590
636
mp_state : Default :: default ( ) ,
0 commit comments